Skip to content

implement vertical align#579

Draft
jkelleyrtp wants to merge 12 commits intolinebender:mainfrom
jkelleyrtp:jk/vertical-align
Draft

implement vertical align#579
jkelleyrtp wants to merge 12 commits intolinebender:mainfrom
jkelleyrtp:jk/vertical-align

Conversation

@jkelleyrtp
Copy link
Copy Markdown

No description provided.

Copy link
Copy Markdown
Collaborator

@nicoburns nicoburns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some initial feedback

Comment thread parley/src/layout/line.rs Outdated
Comment thread parley/src/inline_box.rs

/// A box to be laid out inline with text
#[derive(PartialEq, Debug, Clone)]
pub struct InlineBox {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strictly speaking, this is orthogonal to this PR (but it may be useful to implement it here anyway, and it could also land before this PR), but:

InlineBox ought to gain a first_baseline: Option field. If that is Some then the inline box ought to be aligned using that as it's baseline. If it is None then it would fallback to aligning using the full height of the box (aligning to the bottom of the box), which is the current behaviour.

In Blitz, we'd source this value from Taffy and set it here before running text layout.

Comment on lines +818 to +819
let effective_ascent = (run.metrics.ascent - offset).max(0.0);
let effective_descent = (run.metrics.descent + offset).max(0.0);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not 100% sure, but I think offset should be in the same direction for both of these calculations.

Comment thread parley/src/layout/line_break.rs Outdated
Comment on lines +774 to +776
// Contribute to line metrics considering the offset.
// Inline boxes sit with bottom at baseline by default,
// so effective_ascent = height - offset, effective_descent = offset
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to add a first_baseline: Option<f32> field to inline boxes so in the case that the inline box internally contains text, we can align with the first line of text's baseline rather than the bottom of the box.

Comment thread parley/src/layout/line_break.rs Outdated
Comment on lines +804 to +805
VerticalAlign::TextTop => -(line.metrics.ascent - run.metrics.ascent),
VerticalAlign::TextBottom => line.metrics.descent - run.metrics.descent,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We haven't computed line.metrics.ascent here yet? We only finish computing that at the end of this loop.

Comment on lines +820 to +821
line.metrics.ascent = line.metrics.ascent.max(effective_ascent);
line.metrics.descent = line.metrics.descent.max(effective_descent);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is sufficient in the general case. As text spans form a tree structure, you can end up with nested offsets (imagine a superscript of a superscript). See #291

Perhaps this is landable like this though? I guess we'd need to test how it performs in practice.

Comment thread parley/src/layout/line_break.rs Outdated
Comment on lines +796 to +800
VerticalAlign::Middle => {
let x_height = run
.metrics
.x_height
.unwrap_or(run.metrics.ascent * 0.5);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CSS spec suggests a fallback of font_size * 0.5 https://www.w3.org/TR/css-inline-3/#baseline-synthesis-fonts

Comment thread parley/src/layout/line_break.rs Outdated
Comment on lines +794 to +795
VerticalAlign::Sub => run.metrics.descent,
VerticalAlign::Super => -(run.metrics.ascent * 0.4),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These really ought to be font-specific values taken from the font's BASE table (in Layout::push_run). And added to the run metrics like x_height currently is.

Inline boxes contribute to max_inline_box_above/max_inline_box_below — so line box height correctly spans cross-item extents (overflow:hidden above + text descent below)

Text run half-leading uses run.metrics.line_height instead of the line_height parameter — the parameter is running_line_height which is max(all_cluster_heights, all_inline_box_heights). An inline box with h=135.2 was inflating the text "X"'s half-leading from 3.2 to 51.6, producing the ~174 line_height. This was a pre-existing bug that my inline box tracking change exposed.
@nicoburns
Copy link
Copy Markdown
Collaborator

I think this needs to be split into a few separate PRs:

  1. Adding the new AlignmentBaseline and BaselineShift styles (we may want to skip BaselineSource initially)
  2. Implementing the vertical alignment algorithm in line_break.rs (initial version should probably skip the "strut metrics")
  3. Extracting additional baseline metrics from the font.
  4. Adding baseline support to inline boxes
  5. Root level metrics (aka strut metrics) - this bit is currently adding a lot of complexity, and probably needs some design work. I suggest we try and land the other stuff first.

1, 2, and potentially 3 could potentially all be in the first PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants