layout: Implement support for line-height and vertical-align (#30902)

* layout: Implement support for `line-height` and `vertical-align`

This is an initial implementation of proper `line-height` and
`vertical-align` support. While this change includes the bulk of the
work there are still many missing pieces for full support. In particular
some big missing things are:

 - Flex containers do not properly compute their baselines. The idea is
   to tackle this in a followup change. This causes various flex tests
   to start failing because everything used to be top aligned.
 - The implementation of the line-height quirks (only active in quirks
   mode) are incomplete. While the quirk works in many cases, there are
   still some cases where it is handled incorrectly. This requires more
   redesign and refinement, better suited for a followup.
 - Most of the features are CSS 3 such as precision control of the
   baseline and first and last baselines are not implemented. This
   change gets us close to CSS 2.x support.

While there are many new test passes with this change some tests are
starting to fail. An accounting of new failures:

Tests failing also in Layout 2013:
 - /css/css2/positioning/toogle-abspos-on-relpos-inline-child.html (only passes in Chrome)
 - /css/CSS2/fonts/font-applies-to-001.xht (potentially an issue with font size)

Invalid tests:
 - /css/CSS2/visudet/inline-block-baseline-003.xht
 - /css/CSS2/visudet/inline-block-baseline-004.xht
 - These are are failing in all browsers. See https://bugs.chromium.org/p/chromium/issues/detail?id=1222151.

Missing table support:
 - /_mozilla/mozilla/table_valign_middle.html

Missing `font-size-adjust` support :
 - /css/css-fonts/font-size-adjust-zero-2.html (also failing in 2013)

Incomplete form field support :
- /html/rendering/widgets/the-select-element/option-add-label-quirks.html (label isn't rendered so button isn't the right size in quirks mode due to line height quirk)

Need support for calculating flexbox baseline:
 - /css/css-flexbox/fieldset-baseline-alignment.html
 - /css/css-flexbox/flex-inline.html
 - /css/css-flexbox/flexbox-baseline-multi-line-horiz-001.html
 - /css/css-flexbox/flexbox-baseline-single-item-001a.html
 - /css/css-flexbox/flexbox-baseline-single-item-001b.html

Failing because we don't create anonymous inline boxes for text children of blocks:
- /css/CSS2/linebox/anonymous-inline-inherit-001.html

Passes locally (potentially related to fonts):
 - /css/CSS2/css1/c414-flt-fit-004.xht
 - /css/css-transforms/transform-input-017.html
 - /html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-min-intrinsic-size.html
 - /css/css-fonts/first-available-font-005.html
 - /css/css-fonts/first-available-font-006.html

* Some cleanups after live review with @mukilan

Also update results.
This commit is contained in:
Martin Robinson 2024-01-08 15:49:50 +01:00 committed by GitHub
parent 527119aebb
commit aa073c3dca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
148 changed files with 965 additions and 944 deletions

View file

@ -17,6 +17,7 @@ use crate::geom::{
LengthOrAuto, LogicalRect, LogicalSides, PhysicalPoint, PhysicalRect, PhysicalSides,
PhysicalSize,
};
use crate::style_ext::ComputedValuesExt;
#[derive(Serialize)]
pub(crate) struct BoxFragment {
@ -43,6 +44,11 @@ pub(crate) struct BoxFragment {
/// https://drafts.csswg.org/css2/#clearance
pub clearance: Option<Length>,
/// When this box contains an inline formatting context, this tracks the baseline
/// offset of the last inflow line. This offset is used to propagate baselines to
/// ancestors of `display: inline-block` ancestors.
pub last_baseline_offset: Option<Length>,
pub block_margins_collapsed_with_children: CollapsedBlockMargins,
/// The scrollable overflow of this box fragment.
@ -67,6 +73,7 @@ impl BoxFragment {
border: LogicalSides<Length>,
margin: LogicalSides<Length>,
clearance: Option<Length>,
last_inflow_baseline_offset: Option<Length>,
block_margins_collapsed_with_children: CollapsedBlockMargins,
) -> BoxFragment {
let position = style.get_box().position;
@ -87,6 +94,7 @@ impl BoxFragment {
border,
margin,
clearance,
last_inflow_baseline_offset,
block_margins_collapsed_with_children,
PhysicalSize::new(width_overconstrained, height_overconstrained),
)
@ -101,6 +109,7 @@ impl BoxFragment {
border: LogicalSides<Length>,
margin: LogicalSides<Length>,
clearance: Option<Length>,
mut last_inflow_baseline_offset: Option<Length>,
block_margins_collapsed_with_children: CollapsedBlockMargins,
overconstrained: PhysicalSize<bool>,
) -> BoxFragment {
@ -112,6 +121,17 @@ impl BoxFragment {
acc.union(&child.scrollable_overflow(&containing_block))
});
// From the https://drafts.csswg.org/css-align-3/#baseline-export section on "block containers":
// > However, for legacy reasons if its baseline-source is auto (the initial
// > value) a block-level or inline-level block container that is a scroll container
// > always has a last baseline set, whose baselines all correspond to its block-end
// > margin edge.
if style.establishes_scroll_container() {
last_inflow_baseline_offset = Some(
content_rect.size.block + padding.block_end + border.block_end + margin.block_end,
);
}
BoxFragment {
base: base_fragment_info.into(),
style,
@ -124,6 +144,7 @@ impl BoxFragment {
border,
margin,
clearance,
last_baseline_offset: last_inflow_baseline_offset,
block_margins_collapsed_with_children,
scrollable_overflow_from_children,
overconstrained,
@ -194,9 +215,7 @@ impl BoxFragment {
.border_rect()
.to_physical(self.style.writing_mode, containing_block);
if self.style.get_box().overflow_y != ComputedOverflow::Visible &&
self.style.get_box().overflow_x != ComputedOverflow::Visible
{
if self.style.establishes_scroll_container() {
return overflow;
}