fix(layout): retain grid track areas for positioned descendants

This commit is contained in:
ldm0
2026-10-19 04:52:47 +08:00
parent 281a920d89
commit 5976146db3
4 changed files with 105 additions and 18 deletions
+5 -5
View File
@@ -8,7 +8,7 @@ use crate::{
pub(crate) fn project_resolved_grid_tracks(
style: &taffy::Style<Atom>,
detailed: taffy::DetailedGridInfo<Atom>,
detailed: &taffy::DetailedGridInfo<Atom>,
) -> Option<LayoutResolvedGridTracks> {
let row_line_names = expanded_line_names(
&style.grid_template_rows,
@@ -23,13 +23,13 @@ pub(crate) fn project_resolved_grid_tracks(
usize::from(detailed.columns.auto_repetitions),
)?;
Some(LayoutResolvedGridTracks {
rows: project_tracks(detailed.rows, row_line_names)?,
columns: project_tracks(detailed.columns, column_line_names)?,
rows: project_tracks(&detailed.rows, row_line_names)?,
columns: project_tracks(&detailed.columns, column_line_names)?,
})
}
fn project_tracks(
tracks: taffy::DetailedGridTracksInfo<Atom>,
tracks: &taffy::DetailedGridTracksInfo<Atom>,
explicit_line_names: Vec<Vec<Atom>>,
) -> Option<LayoutResolvedGridTrackList> {
let track_count = usize::from(tracks.negative_implicit_tracks)
@@ -42,7 +42,7 @@ fn project_tracks(
}
let used_track_sizes = tracks
.positions
.into_iter()
.iter()
.map(|position| to_blink_layout_unit(position.end - position.start))
.collect::<Option<Vec<_>>>()?;
Some(LayoutResolvedGridTrackList {
+29 -12
View File
@@ -139,6 +139,7 @@ where
N: Copy + Debug + Eq + Hash,
{
world.resolved_grid_tracks.clear();
world.native_grid_details.clear();
for index in 0..world.boxes.len() {
world.clear_layout_caches(LayoutBoxId::from_index(index));
let layout_box = &mut world.boxes[index];
@@ -1907,25 +1908,33 @@ where
node_id: NodeId,
detailed_grid_info: DetailedGridInfo<Atom>,
) {
let layout_box = &self.boxes[LayoutBoxId::from_taffy(node_id).index()];
if layout_box
let id = LayoutBoxId::from_taffy(node_id);
let layout_box = &self.boxes[id.index()];
let expose_to_cssom = !layout_box
.capability_diagnostics
.contains(&LayoutCapabilityDiagnostic::GridTemplateModeDeferred)
// The current backend reports detailed Grid tracks in physical
// axes. Publishing them for a vertical container would expose its
// width as the used `grid-template-columns` inline size. Keep the
// computed value until logical Grid constraints land in Taffy.
|| !layout_box.style.uses_horizontal_writing_mode()
{
return;
&& layout_box.style.uses_horizontal_writing_mode();
let resolved_grid_tracks = expose_to_cssom
.then(|| {
crate::grid::project_resolved_grid_tracks(
&layout_box.style.taffy,
&detailed_grid_info,
)
})
.flatten();
// The native OOF pass needs these positions even when the browser's
// CSSOM projection deliberately retains the computed track value.
self.native_grid_details.insert(
id,
taffy::DetailedLayoutInfo::Grid(Box::new(detailed_grid_info)),
);
if let Some(tracks) = resolved_grid_tracks {
self.resolved_grid_tracks.insert(id, tracks);
}
let Some(resolved_grid_tracks) =
crate::grid::project_resolved_grid_tracks(&layout_box.style.taffy, detailed_grid_info)
else {
return;
};
self.resolved_grid_tracks
.insert(LayoutBoxId::from_taffy(node_id), resolved_grid_tracks);
}
}
@@ -3270,6 +3279,14 @@ impl<N: Copy + Debug + Eq + Hash> taffy::LayoutContainingBlock for LayoutWorld<N
fn get_oof_item_style(&self, node: NodeId) -> Self::OofItemStyle<'_> {
self.get_core_container_style(node)
}
fn get_detailed_layout_info(&self, node: NodeId) -> &taffy::DetailedLayoutInfo<Atom> {
if self.is_viewport_taffy_node(node) {
return &taffy::DetailedLayoutInfo::None;
}
self.native_grid_details
.get(&LayoutBoxId::from_taffy(node))
.unwrap_or(&taffy::DetailedLayoutInfo::None)
}
fn get_containing_block_claims(&self, _: NodeId) -> taffy::ContainingBlockClaims {
// prepare_layout_tree has already attached every positioned box to
// its CSS containing block. Internal static-position probes retain
+4 -1
View File
@@ -1,7 +1,7 @@
use std::{collections::HashMap, fmt::Debug, hash::Hash, num::NonZeroU32, sync::Arc};
use style::Atom;
use taffy::{Cache, Layout, Point, Style};
use taffy::{Cache, DetailedLayoutInfo, Layout, Point, Style};
use crate::{
LayoutCssImageReference, LayoutElementSemantics, LayoutError, LayoutPoint, LayoutPseudo,
@@ -639,6 +639,8 @@ where
/// Used Grid tracks for actual owners. Their canonical result is frozen
/// for CSSOM before this pass-local map is released.
pub(crate) resolved_grid_tracks: HashMap<LayoutBoxId, LayoutResolvedGridTracks>,
/// Native track positions and names read by Taffy's out-of-flow pass.
pub(crate) native_grid_details: HashMap<LayoutBoxId, DetailedLayoutInfo<Atom>>,
pub(crate) source_mapping: HashMap<N, LayoutBoxId>,
pub(crate) display_contents_mapping: HashMap<N, Vec<LayoutBoxId>>,
pub(crate) root: LayoutBoxId,
@@ -669,6 +671,7 @@ where
box_caches: Vec::new(),
collapsed_table_borders: HashMap::new(),
resolved_grid_tracks: HashMap::new(),
native_grid_details: HashMap::new(),
source_mapping: HashMap::new(),
display_contents_mapping: HashMap::new(),
root: LayoutBoxId::from_index(0),
+67
View File
@@ -709,6 +709,73 @@ fn grid_item_placement_and_self_alignment_use_the_selected_grid_area() {
);
}
#[test]
fn absolute_grid_items_use_retained_track_areas_in_both_directions() {
for (direction, x) in [
(taffy::Direction::Ltr, 135.0),
(taffy::Direction::Rtl, 95.0),
] {
let source = FixtureSource {
nodes: vec![
FixtureNode::div("grid", vec![1]),
FixtureNode::div("positioned", Vec::new()),
],
};
let mut styles = FixtureStyles::default();
styles.0.insert(
0,
resolved(
LayoutDisplay::Grid,
Style {
display: Display::Grid,
direction,
box_sizing: BoxSizing::ContentBox,
size: Size {
width: length(400.0),
height: length(300.0),
},
padding: Rect::length(10.0),
border: Rect::length(5.0),
gap: Size {
width: length(20.0),
height: length(10.0),
},
grid_template_columns: vec![length(100.0), length(200.0)],
grid_template_rows: vec![length(50.0), length(100.0)],
..Style::default()
},
PaintColor::TRANSPARENT,
)
.with_position(LayoutPosition::Relative),
);
styles.0.insert(
1,
resolved(
LayoutDisplay::Block,
Style {
inset: Rect::length(0.0),
grid_column: Line {
start: line(2),
end: line(3),
},
grid_row: Line {
start: line(2),
end: line(3),
},
..Style::default()
},
RED,
)
.with_position(LayoutPosition::Absolute),
);
let snapshot = render(&source, &mut styles, PaintViewport::new(800, 600, 1.0));
assert_rect(
solid_rect(&snapshot, RED),
PaintRect::new(x, 75.0, 200.0, 100.0),
);
}
}
#[test]
fn grid_container_justify_items_center_shrink_wraps_an_auto_sized_item() {
let source = FixtureSource {