Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

### Fixed

- Grid: items with an `auto` block-axis margin no longer participate in baseline alignment, per [CSS Align §9.5](https://www.w3.org/TR/css-align-3/#baseline-align-self). Such items are no longer baseline-shimmed (their auto margin aligns them instead), and they are no longer selected as the item the grid container's own first baseline is generated from, matching the existing flexbox behaviour

- Flexbox: a flex item's cross-axis size is now only treated as definite (for resolving percentage sizes of its descendants) when the item is stretched or its cross size style resolves to a definite size, per [CSS Flexbox §4.5](https://www.w3.org/TR/css-flexbox-1/#definite-sizes). Previously content-derived cross sizes of non-stretched items were incorrectly used as percentage resolution bases

- Block: a container's `min-height` alone no longer acts as the resolution basis for the percentage heights of its children when the container's own height is indefinite. Per [CSS 2 §10.5](https://www.w3.org/TR/CSS22/visudet.html#the-height-property), such percentages resolve as `auto`
Expand Down
18 changes: 8 additions & 10 deletions src/compute/grid/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! <https://www.w3.org/TR/css-grid-1>
use crate::geometry::{AbsoluteAxis, AbstractAxis, InBothAbsAxis};
use crate::geometry::{Line, Rect, Size};
use crate::style::{AlignItems, AlignSelf, AvailableSpace, Overflow, Position};
use crate::style::{AlignItems, AvailableSpace, Overflow, Position};
use crate::tree::{Baselines, Layout, LayoutInput, LayoutOutput, LayoutPartialTreeExt, NodeId, RunMode, SizingMode};
use crate::util::debug::debug_log;
use crate::util::sys::{f32_max, f32_min, GridTrackVec, Vec};
Expand Down Expand Up @@ -305,7 +305,7 @@ pub fn compute_grid_layout<Tree: LayoutGridContainer>(
determine_if_item_crosses_flexible_or_intrinsic_tracks(&mut items, &columns, &rows);

// Determine if the grid has any baseline aligned items
let has_baseline_aligned_item = items.iter().any(|item| item.align_self == AlignSelf::BASELINE);
let has_baseline_aligned_item = items.iter().any(|item| item.participates_in_baseline_alignment());

// Run track sizing algorithm for Inline axis
track_sizing_algorithm(
Expand Down Expand Up @@ -795,14 +795,12 @@ pub fn compute_grid_layout<Tree: LayoutGridContainer>(
// Create a slice of all of the items start in this row (taking advantage of the fact that we have just sorted the array)
let first_row_items = &items[0..].split(|item| item.row_indexes.start != first_row).next().unwrap();

// Check if any items in *this row* are baseline aligned
let row_has_baseline_item = first_row_items.iter().any(|item| item.align_self == AlignSelf::BASELINE);

let item = if row_has_baseline_item {
first_row_items.iter().find(|item| item.align_self == AlignSelf::BASELINE).unwrap()
} else {
&first_row_items[0]
};
// Check if any items in *this row* participate in baseline alignment
// (items with an auto block-axis margin do not participate: https://www.w3.org/TR/css-align-3/#baseline-align-self)
let item = first_row_items
.iter()
.find(|item| item.participates_in_baseline_alignment())
.unwrap_or(&first_row_items[0]);

item.y_position + item.baseline.unwrap_or(item.height)
};
Expand Down
26 changes: 18 additions & 8 deletions src/compute/grid/track_sizing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! <https://www.w3.org/TR/css-grid-1/#layout-algorithm>
use super::types::{GridItem, GridTrack, TrackCounts};
use crate::geometry::{AbstractAxis, Line, Size};
use crate::style::{AlignContent, AlignContentKeyword, AlignSelf, AvailableSpace};
use crate::style::{AlignContent, AlignContentKeyword, AvailableSpace};
use crate::style_helpers::TaffyMinContent;
use crate::tree::{LayoutPartialTree, LayoutPartialTreeExt, SizingMode};
use crate::util::sys::{f32_max, f32_min, Vec};
Expand Down Expand Up @@ -493,13 +493,17 @@ fn resolve_item_baselines(
// Count how many items in *this row* are baseline aligned
// If a row has one or zero items participating in baseline alignment then baseline alignment is a no-op
// for those items and we skip further computations for that row
let row_baseline_item_count = row_items.iter().filter(|item| item.align_self == AlignSelf::BASELINE).count();
let row_baseline_item_count = row_items.iter().filter(|item| item.participates_in_baseline_alignment()).count();
if row_baseline_item_count <= 1 {
continue;
}

// Compute the baselines of all items in the row
// Compute the baselines of all items in the row participating in baseline alignment
for item in row_items.iter_mut() {
if !item.participates_in_baseline_alignment() {
continue;
}

let measured_size_and_baselines = tree.perform_child_layout(
item.node,
Size::NONE,
Expand All @@ -526,13 +530,19 @@ fn resolve_item_baselines(
);
}

// Compute the max baseline of all items in the row
let row_max_baseline =
row_items.iter().map(|item| item.baseline.unwrap_or(0.0)).max_by(|a, b| a.total_cmp(b)).unwrap();
// Compute the max baseline of all items in the row participating in baseline alignment
let row_max_baseline = row_items
.iter()
.filter(|item| item.participates_in_baseline_alignment())
.map(|item| item.baseline.unwrap_or(0.0))
.max_by(|a, b| a.total_cmp(b))
.unwrap();

// Compute the baseline shim for each item in the row
// Compute the baseline shim for each item in the row participating in baseline alignment
for item in row_items.iter_mut() {
item.baseline_shim = row_max_baseline - item.baseline.unwrap_or(0.0);
if item.participates_in_baseline_alignment() {
item.baseline_shim = row_max_baseline - item.baseline.unwrap_or(0.0);
}
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/compute/grid/types/grid_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,14 @@ impl GridItem {
}
}

/// Returns true if the item participates in baseline alignment: it has `align-self: baseline`
/// and neither of its block-axis margins are `auto`.
/// See <https://www.w3.org/TR/css-align-3/#baseline-align-self>
#[inline(always)]
pub fn participates_in_baseline_alignment(&self) -> bool {
self.align_self == AlignSelf::BASELINE && !self.margin.top.is_auto() && !self.margin.bottom.is_auto()
}

/// This item's placement in the specified axis in OriginZero coordinates
pub fn placement(&self, axis: AbstractAxis) -> Line<OriginZeroLine> {
match axis {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script src="../../scripts/gentest/test_helper.js"></script>
<link rel="stylesheet" type="text/css" href="../../scripts/gentest/test_base_style.css">
<title>
An item with an auto block-axis margin does not participate in baseline alignment and is
not baseline-shimmed: it is bottom-aligned by its auto margin instead
</title>
</head>
<body>

<div id="test-root" style="display: grid; grid-auto-flow: column; grid-auto-columns: 40px; align-items: baseline; width: 120px;">
<div style="display: grid; height: 20px;"></div>
<div style="display: grid; height: 30px;"></div>
<div style="display: grid; margin-top: auto; height: 25px;">
<div style="display: grid; align-self: start; height: 5px;"></div>
</div>
</div>

</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script src="../../scripts/gentest/test_helper.js"></script>
<link rel="stylesheet" type="text/css" href="../../scripts/gentest/test_base_style.css">
<title>
An item with an auto block-axis margin does not participate in baseline alignment, so the
grid container's baseline is generated from the row's first item instead
</title>
</head>
<body>

<div id="test-root" style="display: grid; grid-template-columns: 60px 60px; align-items: baseline; width: 120px; height: 80px;">
<div style="display: grid; width: 50px; height: 30px;"></div>
<div style="display: grid; grid-auto-flow: column; grid-auto-rows: 40px; grid-auto-columns: 25px; width: 50px;">
<div style="display: grid; height: 20px;"></div>
<div style="display: grid; align-self: baseline; margin-top: auto; height: 10px;"></div>
</div>
</div>

</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<test name="grid_align_items_baseline_child_auto_margin__border_box_ltr" use-rounding="true">
<viewport width="max-content" height="max-content"/>
<input>
<div display="grid" direction="ltr" align-items="baseline" width="120px" grid-auto-flow="column" grid-auto-columns="40px">
<div display="grid" direction="ltr" height="20px"/>
<div display="grid" direction="ltr" height="30px"/>
<div display="grid" direction="ltr" height="25px" margin-top="auto">
<div display="grid" direction="ltr" align-self="start" height="5px"/>
</div>
</div>
</input>
<expectations>
<node x="0" y="0" width="120" height="30">
<node x="0" y="10" width="40" height="20"/>
<node x="40" y="0" width="40" height="30"/>
<node x="80" y="5" width="40" height="25">
<node x="0" y="0" width="40" height="5"/>
</node>
</node>
</expectations>
</test>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<test name="grid_align_items_baseline_child_auto_margin__border_box_rtl" use-rounding="true">
<viewport width="max-content" height="max-content"/>
<input>
<div display="grid" direction="rtl" align-items="baseline" width="120px" grid-auto-flow="column" grid-auto-columns="40px">
<div display="grid" direction="rtl" height="20px"/>
<div display="grid" direction="rtl" height="30px"/>
<div display="grid" direction="rtl" height="25px" margin-top="auto">
<div display="grid" direction="rtl" align-self="start" height="5px"/>
</div>
</div>
</input>
<expectations>
<node x="0" y="0" width="120" height="30">
<node x="80" y="10" width="40" height="20"/>
<node x="40" y="0" width="40" height="30"/>
<node x="0" y="5" width="40" height="25">
<node x="0" y="0" width="40" height="5"/>
</node>
</node>
</expectations>
</test>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<test name="grid_align_items_baseline_child_auto_margin__content_box_ltr" use-rounding="true">
<viewport width="max-content" height="max-content"/>
<input>
<div display="grid" box-sizing="content-box" direction="ltr" align-items="baseline" width="120px" grid-auto-flow="column" grid-auto-columns="40px">
<div display="grid" box-sizing="content-box" direction="ltr" height="20px"/>
<div display="grid" box-sizing="content-box" direction="ltr" height="30px"/>
<div display="grid" box-sizing="content-box" direction="ltr" height="25px" margin-top="auto">
<div display="grid" box-sizing="content-box" direction="ltr" align-self="start" height="5px"/>
</div>
</div>
</input>
<expectations>
<node x="0" y="0" width="120" height="30">
<node x="0" y="10" width="40" height="20"/>
<node x="40" y="0" width="40" height="30"/>
<node x="80" y="5" width="40" height="25">
<node x="0" y="0" width="40" height="5"/>
</node>
</node>
</expectations>
</test>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<test name="grid_align_items_baseline_child_auto_margin__content_box_rtl" use-rounding="true">
<viewport width="max-content" height="max-content"/>
<input>
<div display="grid" box-sizing="content-box" direction="rtl" align-items="baseline" width="120px" grid-auto-flow="column" grid-auto-columns="40px">
<div display="grid" box-sizing="content-box" direction="rtl" height="20px"/>
<div display="grid" box-sizing="content-box" direction="rtl" height="30px"/>
<div display="grid" box-sizing="content-box" direction="rtl" height="25px" margin-top="auto">
<div display="grid" box-sizing="content-box" direction="rtl" align-self="start" height="5px"/>
</div>
</div>
</input>
<expectations>
<node x="0" y="0" width="120" height="30">
<node x="80" y="10" width="40" height="20"/>
<node x="40" y="0" width="40" height="30"/>
<node x="0" y="5" width="40" height="25">
<node x="0" y="0" width="40" height="5"/>
</node>
</node>
</expectations>
</test>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<test name="grid_baseline_child_auto_margin_container_baseline__border_box_ltr" use-rounding="true">
<viewport width="max-content" height="max-content"/>
<input>
<div display="grid" direction="ltr" align-items="baseline" width="120px" height="80px" grid-template-columns="60px 60px">
<div display="grid" direction="ltr" width="50px" height="30px"/>
<div display="grid" direction="ltr" width="50px" grid-auto-flow="column" grid-auto-rows="40px" grid-auto-columns="25px">
<div display="grid" direction="ltr" height="20px"/>
<div display="grid" direction="ltr" align-self="baseline" height="10px" margin-top="auto"/>
</div>
</div>
</input>
<expectations>
<node x="0" y="0" width="120" height="80">
<node x="0" y="0" width="50" height="30"/>
<node x="60" y="10" width="50" height="40">
<node x="0" y="0" width="25" height="20"/>
<node x="25" y="30" width="25" height="10"/>
</node>
</node>
</expectations>
</test>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<test name="grid_baseline_child_auto_margin_container_baseline__border_box_rtl" use-rounding="true">
<viewport width="max-content" height="max-content"/>
<input>
<div display="grid" direction="rtl" align-items="baseline" width="120px" height="80px" grid-template-columns="60px 60px">
<div display="grid" direction="rtl" width="50px" height="30px"/>
<div display="grid" direction="rtl" width="50px" grid-auto-flow="column" grid-auto-rows="40px" grid-auto-columns="25px">
<div display="grid" direction="rtl" height="20px"/>
<div display="grid" direction="rtl" align-self="baseline" height="10px" margin-top="auto"/>
</div>
</div>
</input>
<expectations>
<node x="0" y="0" width="120" height="80">
<node x="70" y="0" width="50" height="30"/>
<node x="10" y="10" width="50" height="40">
<node x="25" y="0" width="25" height="20"/>
<node x="0" y="30" width="25" height="10"/>
</node>
</node>
</expectations>
</test>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<test name="grid_baseline_child_auto_margin_container_baseline__content_box_ltr" use-rounding="true">
<viewport width="max-content" height="max-content"/>
<input>
<div display="grid" box-sizing="content-box" direction="ltr" align-items="baseline" width="120px" height="80px" grid-template-columns="60px 60px">
<div display="grid" box-sizing="content-box" direction="ltr" width="50px" height="30px"/>
<div display="grid" box-sizing="content-box" direction="ltr" width="50px" grid-auto-flow="column" grid-auto-rows="40px" grid-auto-columns="25px">
<div display="grid" box-sizing="content-box" direction="ltr" height="20px"/>
<div display="grid" box-sizing="content-box" direction="ltr" align-self="baseline" height="10px" margin-top="auto"/>
</div>
</div>
</input>
<expectations>
<node x="0" y="0" width="120" height="80">
<node x="0" y="0" width="50" height="30"/>
<node x="60" y="10" width="50" height="40">
<node x="0" y="0" width="25" height="20"/>
<node x="25" y="30" width="25" height="10"/>
</node>
</node>
</expectations>
</test>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<test name="grid_baseline_child_auto_margin_container_baseline__content_box_rtl" use-rounding="true">
<viewport width="max-content" height="max-content"/>
<input>
<div display="grid" box-sizing="content-box" direction="rtl" align-items="baseline" width="120px" height="80px" grid-template-columns="60px 60px">
<div display="grid" box-sizing="content-box" direction="rtl" width="50px" height="30px"/>
<div display="grid" box-sizing="content-box" direction="rtl" width="50px" grid-auto-flow="column" grid-auto-rows="40px" grid-auto-columns="25px">
<div display="grid" box-sizing="content-box" direction="rtl" height="20px"/>
<div display="grid" box-sizing="content-box" direction="rtl" align-self="baseline" height="10px" margin-top="auto"/>
</div>
</div>
</input>
<expectations>
<node x="0" y="0" width="120" height="80">
<node x="70" y="0" width="50" height="30"/>
<node x="10" y="10" width="50" height="40">
<node x="25" y="0" width="25" height="20"/>
<node x="0" y="30" width="25" height="10"/>
</node>
</node>
</expectations>
</test>
Loading