linebender / linebender/parley

Vertical alignment and the concept of a "parent" font and style

Open
#291 12 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
736
Forks
120
Avg merge
1d 3h
Merged PRs (30d)
53

Description

There was some discussion in https://github.com/linebender/parley/issues/25 about 1) vertical alignment of inline boxes and 2) a tree-based vs. flat style structure. That discussion seemed to show a preference for a tree-based API, but https://github.com/linebender/parley/issues/279 suggests that the layout algorithm will eventually want to operate on a flat list of style spans.

I need to implement some sort of vertical alignment for inline boxes, and ran into an API design issue when looking at the way CSS does it (and this library seems to have the goal of matching CSS' API).

I still don't fully understand the way that the CSS inline layout algorithm works, but vertical alignment of an "inline-level box" (in Parley's case, either an `InlineBox` or a span of text) is done relative to the baselines of its "parent". See [4. Baseline Alignment](https://drafts.csswg.org/css-inline/#alignment) (emphasis mine):

> While most CSS [formatting contexts](https://drafts.csswg.org/css-display-4/#formatting-context) position content by aligning boxes with respect to their container’s edges, [inline layout](https://drafts.csswg.org/css-inline/#inline-layout) positions boxes in the [block axis](https://drafts.csswg.org/css-writing-modes-4/#block-axis) by aligning them with respect to each other using their [baselines](https://drafts.csswg.org/css-inline/#baseline).
>
> More specifically, (unless using a [line-relative shift value](https://drafts.csswg.org/css-inline/#line-relative-shift-values)) each glyph or [inline-level box](https://drafts.csswg.org/css-display-3/#inline-level-box) is aligned in the [block axis](https://drafts.csswg.org/css-writing-modes-4/#block-axis) by positioning its [alignment baseline](https://drafts.csswg.org/css-inline/#alignment-baseline) to match the corresponding [baseline](https://drafts.csswg.org/css-inline/#baseline) of **its parent** (which is its [alignment context](https://drafts.csswg.org/css-align-3/#shared-alignment-context)), and then is potentially shifted from that position according to its [post-alignment shift](https://drafts.csswg.org/css-inline/#post-alignment-shift).
>
> When aligning a [box](https://drafts.csswg.org/css-display-4/#box), the [alignment baseline](https://drafts.csswg.org/css-inline/#alignment-baseline) is chosen according to its [alignment-baseline](https://drafts.csswg.org/css-inline/#propdef-alignment-baseline) and [baseline-source](https://drafts.csswg.org/css-inline/#propdef-baseline-source) values (see shorthand [vertical-align](https://drafts.csswg.org/css-inline/#propdef-vertical-align)), and defaults to matching **the parent’s** [dominant-baseline](https://drafts.csswg.org/css-inline/#propdef-dominant-baseline). For a glyph, the alignment baseline is always determined by **the parent’s** [dominant baseline](https://drafts.csswg.org/css-inline/#dominant-baseline).

When aligning inline boxes with other inline boxes, their baseline sets are [also based on inherited font settings](https://drafts.csswg.org/css-align-3/#baseline-export):

> The first/last [baseline set](https://drafts.csswg.org/css-align-3/#baseline-set) of a line box is [generated](https://drafts.csswg.org/css-align-3/#generate-baselines) from the dominant baseline and the font settings of its [root inline box](https://drafts.csswg.org/css-inline-3/#root-inline-box).

If my mental model of CSS is correct, then a workable API for Parley that would allow implementing HTML/CSS layout on top of it would be:

- A `Layout` has an explicit "root style"/"parent style". Right now, `RangedStyleBuilder` and `TreeStyleBuilder` have a default and root style respectively, but they're conceptually treated the same as any other style node, when they need to be treated specially for the purpose of doing layout.
- Beyond this, I think it's OK to use a flattened set of styled spans for everything else.
- We can then use this "root style" to get the font metrics / baseline set for alignment purposes.
- This implies that `Style` (or at least `ResolvedStyle`) should have an API for fetching font metrics (if only for use internally). Right now, there doesn't seem to be a way to get them until shaping actually occurs. They depend on font variations, but those will probably also be specified in `Style`.
- `Layout` could have APIs to access its root style and its [baseline sets](https://drafts.csswg.org/css-align-3/#baseline-set).
- `InlineBox` would allow you to specify *its* [baseline sets](https://drafts.csswg.org/css-align-3/#baseline-set). Combined with the above API, this would allow the API consumer to implement nested layout by recursively rendering `Layout`s inside-out, starting with the leaf nodes and turning them into `InlineBox`es positioned in the higher-up `Layout`s.

Does this sound like a reasonable API surface?

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the discussion in issues 25 and 279, then review the roles of RangedStyleBuilder, TreeStyleBuilder, Layout, Style, ResolvedStyle, and InlineBox described here. Compare the proposed root-style, font-metrics, baseline-set, and flattened-span APIs with the cited CSS inline-layout specifications. Done would require an agreed API direction and implementation scope; this issue does not currently identify a specific file or test.

Written by the indexing model from the issue text.

Assessment

Tech stack
css, rust
Domain
computer-graphics, design
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.