Skip to content

Commit a03a332

Browse files
committed
Named grid lines and areas WIP
Signed-off-by: Nico Burns <[email protected]>
1 parent 3d585ec commit a03a332

File tree

11 files changed

+389
-48
lines changed

11 files changed

+389
-48
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ default = [
3939
"taffy_tree",
4040
"flexbox",
4141
"grid",
42+
"grid_named",
4243
"block_layout",
4344
"calc",
4445
"content_size",
@@ -54,6 +55,8 @@ block_layout = []
5455
flexbox = []
5556
## Enables the CSS Grid layout algorithm. See [`compute_grid_layout`](crate::compute_grid_layout).
5657
grid = ["alloc", "dep:grid"]
58+
## Enables names grid lines and areas for the grid layout algorithm
59+
grid_named = ["grid"]
5760
## Enables calc() values for all layout algorithms
5861
calc = []
5962
## Causes all algorithms to compute and output a content size for each node

src/compute/grid/explicit_grid.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::{GridContainerStyle, MaybeResolve};
1313
pub(crate) fn compute_explicit_grid_size_in_axis(
1414
style: &impl GridContainerStyle,
1515
template: &[TrackSizingFunction],
16+
grid_area_track_count: u16,
1617
inner_container_size: Size<Option<f32>>,
1718
resolve_calc_value: impl Fn(*const (), f32) -> f32,
1819
axis: AbsoluteAxis,
@@ -174,7 +175,8 @@ pub(crate) fn compute_explicit_grid_size_in_axis(
174175
}
175176
};
176177

177-
non_auto_repeating_track_count + (repetition_track_count * num_repetitions)
178+
let grid_template_track_count = non_auto_repeating_track_count + (repetition_track_count * num_repetitions);
179+
(grid_template_track_count).max(grid_area_track_count)
178180
}
179181

180182
/// Resolve the track sizing functions of explicit tracks, automatically created tracks, and gutters

src/compute/grid/implicit_grid.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//! to reduce the number of allocations required when creating a grid.
33
use crate::geometry::Line;
44
use crate::style::{GenericGridPlacement, GridPlacement};
5-
use crate::GridItemStyle;
5+
use crate::{CheapCloneStr, GridItemStyle};
66
use core::cmp::{max, min};
77

88
use super::types::TrackCounts;
@@ -91,8 +91,8 @@ fn get_known_child_positions<'a, S: GridItemStyle + 'a>(
9191
///
9292
/// Values are returned in origin-zero coordinates
9393
#[inline]
94-
fn child_min_line_max_line_span(
95-
line: Line<GridPlacement>,
94+
fn child_min_line_max_line_span<S: CheapCloneStr>(
95+
line: Line<GridPlacement<S>>,
9696
explicit_track_count: u16,
9797
) -> (OriginZeroLine, OriginZeroLine, u16) {
9898
use GenericGridPlacement::*;
@@ -104,7 +104,8 @@ fn child_min_line_max_line_span(
104104
// D. If the placement contains only a span for a named line, replace it with a span of 1.
105105

106106
// Convert line into origin-zero coordinates before attempting to analyze
107-
let oz_line = line.into_origin_zero(explicit_track_count);
107+
// We ignore named lines here as they are accounted for separately
108+
let oz_line = line.into_origin_zero_ignoring_named(explicit_track_count);
108109

109110
let min = match (oz_line.start, oz_line.end) {
110111
// Both tracks specified
@@ -156,8 +157,8 @@ fn child_min_line_max_line_span(
156157

157158
// Calculate span only for indefinitely placed items as we don't need for other items (whose required space will
158159
// be taken into account by min and max)
159-
let span = match (line.start, line.end) {
160-
(Auto | Span(_), Auto | Span(_)) => line.indefinite_span(),
160+
let span = match (oz_line.start, oz_line.end) {
161+
(Auto | Span(_), Auto | Span(_)) => oz_line.indefinite_span(),
161162
_ => 1,
162163
};
163164

src/compute/grid/mod.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::util::MaybeMath;
1212
use crate::util::{MaybeResolve, ResolveOrZero};
1313
use crate::{
1414
style_helpers::*, AlignContent, BoxGenerationMode, BoxSizing, CoreStyle, GridContainerStyle, GridItemStyle,
15-
JustifyContent, LayoutGridContainer,
15+
JustifyContent, LayoutGridContainer, LayoutPartialTree,
1616
};
1717
use alignment::{align_and_position_item, align_tracks};
1818
use explicit_grid::{compute_explicit_grid_size_in_axis, initialize_grid_tracks};
@@ -21,7 +21,7 @@ use placement::place_grid_items;
2121
use track_sizing::{
2222
determine_if_item_crosses_flexible_or_intrinsic_tracks, resolve_item_track_indexes, track_sizing_algorithm,
2323
};
24-
use types::{CellOccupancyMatrix, GridTrack};
24+
use types::{CellOccupancyMatrix, GridTrack, NamedLineResolver};
2525

2626
#[cfg(feature = "detailed_layout_info")]
2727
use types::{GridItem, GridTrackKind, TrackCounts};
@@ -105,6 +105,13 @@ pub fn compute_grid_layout<Tree: LayoutGridContainer>(
105105
let grid_auto_columms = style.grid_auto_columns();
106106
let grid_auto_rows = style.grid_auto_rows();
107107

108+
// type CustomIdent<'a> = <<Tree as LayoutGridContainer>::GridContainerStyle<'a> as GridContainerStyle>::CustomIdent;
109+
let name_resolver = NamedLineResolver::<
110+
<<Tree as LayoutPartialTree>::CoreContainerStyle<'_> as CoreStyle>::CustomIdent,
111+
>::new(style.grid_template_areas());
112+
let grid_area_column_count = name_resolver.area_column_count();
113+
let grid_area_row_count = name_resolver.area_row_count();
114+
108115
let constrained_available_space = known_dimensions
109116
.or(preferred_size)
110117
.map(|size| size.map(AvailableSpace::Definite))
@@ -156,13 +163,15 @@ pub fn compute_grid_layout<Tree: LayoutGridContainer>(
156163
let explicit_col_count = compute_explicit_grid_size_in_axis(
157164
&style,
158165
grid_template_columms.borrow(),
166+
grid_area_column_count,
159167
auto_fit_container_size,
160168
|val, basis| tree.calc(val, basis),
161169
AbsoluteAxis::Horizontal,
162170
);
163171
let explicit_row_count = compute_explicit_grid_size_in_axis(
164172
&style,
165173
grid_template_rows.borrow(),
174+
grid_area_row_count,
166175
auto_fit_container_size,
167176
|val, basis| tree.calc(val, basis),
168177
AbsoluteAxis::Vertical,
@@ -193,6 +202,7 @@ pub fn compute_grid_layout<Tree: LayoutGridContainer>(
193202
style.grid_auto_flow(),
194203
align_items.unwrap_or(AlignItems::Stretch),
195204
justify_items.unwrap_or(AlignItems::Stretch),
205+
&name_resolver,
196206
);
197207

198208
// Extract track counts from previous step (auto-placement can expand the number of tracks)
@@ -541,17 +551,17 @@ pub fn compute_grid_layout<Tree: LayoutGridContainer>(
541551
if child_style.position() == Position::Absolute {
542552
// Convert grid-col-{start/end} into Option's of indexes into the columns vector
543553
// The Option is None if the style property is Auto and an unresolvable Span
544-
let maybe_col_indexes = child_style
545-
.grid_column()
554+
let maybe_col_indexes = name_resolver
555+
.resolve_column_names(&child_style.grid_column())
546556
.into_origin_zero(final_col_counts.explicit)
547557
.resolve_absolutely_positioned_grid_tracks()
548558
.map(|maybe_grid_line| {
549559
maybe_grid_line.map(|line: OriginZeroLine| line.into_track_vec_index(final_col_counts))
550560
});
551561
// Convert grid-row-{start/end} into Option's of indexes into the row vector
552562
// The Option is None if the style property is Auto and an unresolvable Span
553-
let maybe_row_indexes = child_style
554-
.grid_row()
563+
let maybe_row_indexes = name_resolver
564+
.resolve_row_names(&child_style.grid_row())
555565
.into_origin_zero(final_row_counts.explicit)
556566
.resolve_absolutely_positioned_grid_tracks()
557567
.map(|maybe_grid_line| {

src/compute/grid/placement.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
//! Implements placing items in the grid and resolving the implicit grid.
22
//! <https://www.w3.org/TR/css-grid-1/#placement>
33
use super::types::{CellOccupancyMatrix, CellOccupancyState, GridItem};
4-
use super::OriginZeroLine;
4+
use super::{NamedLineResolver, OriginZeroLine};
55
use crate::geometry::Line;
66
use crate::geometry::{AbsoluteAxis, InBothAbsAxis};
77
use crate::style::{AlignItems, GridAutoFlow, OriginZeroGridPlacement};
88
use crate::tree::NodeId;
99
use crate::util::sys::Vec;
10-
use crate::GridItemStyle;
10+
use crate::{CoreStyle, GridItemStyle};
1111

1212
/// 8.5. Grid Item Placement Algorithm
1313
/// Place items into the grid, generating new rows/column into the implicit grid as required
@@ -20,6 +20,7 @@ pub(super) fn place_grid_items<'a, S, ChildIter>(
2020
grid_auto_flow: GridAutoFlow,
2121
align_items: AlignItems,
2222
justify_items: AlignItems,
23+
named_line_resolver: &NamedLineResolver<<S as CoreStyle>::CustomIdent>,
2324
) where
2425
S: GridItemStyle + 'a,
2526
ChildIter: Iterator<Item = (usize, NodeId, S)>,
@@ -32,10 +33,12 @@ pub(super) fn place_grid_items<'a, S, ChildIter>(
3233
let explicit_row_count = cell_occupancy_matrix.track_counts(AbsoluteAxis::Vertical).explicit;
3334
move |(index, node, style): (usize, NodeId, S)| -> (_, _, _, S) {
3435
let origin_zero_placement = InBothAbsAxis {
35-
horizontal: style
36-
.grid_column()
36+
horizontal: named_line_resolver
37+
.resolve_column_names(&style.grid_column())
3738
.map(|placement| placement.into_origin_zero_placement(explicit_col_count)),
38-
vertical: style.grid_row().map(|placement| placement.into_origin_zero_placement(explicit_row_count)),
39+
vertical: named_line_resolver
40+
.resolve_row_names(&style.grid_row())
41+
.map(|placement| placement.into_origin_zero_placement(explicit_row_count)),
3942
};
4043
(index, node, origin_zero_placement, style)
4144
}

src/compute/grid/types/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod coordinates;
44
mod grid_item;
55
mod grid_track;
66
mod grid_track_counts;
7+
mod named;
78

89
// Publish only locally in the grid module
910
pub(super) use cell_occupancy::{CellOccupancyMatrix, CellOccupancyState};
@@ -15,6 +16,8 @@ pub(super) use grid_track_counts::TrackCounts;
1516
#[allow(unused_imports)]
1617
pub(super) use grid_track::GridTrackKind;
1718

19+
pub(super) use named::NamedLineResolver;
20+
1821
// pub(super) enum GridPosition {
1922
// Auto,
2023
// LineIndex(i16),

src/compute/grid/types/named.rs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
use crate::{
2+
CheapCloneStr, GenericGridPlacement, GridAreaAxis, GridAreaEnd, GridPlacement, GridTemplateArea, Line,
3+
NonNamedGridPlacement,
4+
};
5+
use core::borrow::Borrow;
6+
use std::{
7+
collections::HashMap,
8+
hash::{Hash, Hasher},
9+
};
10+
11+
/// Wrap an `AsRef<str>` type with a type which implements Hash by first
12+
/// deferring to the underlying `&str`'s implementation of Hash.
13+
#[derive(Debug, Clone)]
14+
pub(crate) struct StrHasher<T: CheapCloneStr>(pub T);
15+
impl<T: CheapCloneStr> Hash for StrHasher<T> {
16+
fn hash<H: Hasher>(&self, state: &mut H) {
17+
// Dele
18+
self.0.as_ref().hash(state)
19+
}
20+
}
21+
impl<T: CheapCloneStr> PartialEq for StrHasher<T> {
22+
fn eq(&self, other: &Self) -> bool {
23+
other.0.as_ref() == self.0.as_ref()
24+
}
25+
}
26+
impl<T: CheapCloneStr> Borrow<str> for StrHasher<T> {
27+
fn borrow(&self) -> &str {
28+
self.0.as_ref()
29+
}
30+
}
31+
impl<T: CheapCloneStr> Eq for StrHasher<T> {}
32+
33+
/// Resolve lines for
34+
pub(crate) struct NamedLineResolver<S: CheapCloneStr> {
35+
lines: HashMap<StrHasher<S>, i16>,
36+
areas: HashMap<StrHasher<S>, GridTemplateArea<S>>,
37+
area_column_count: u16,
38+
area_row_count: u16,
39+
}
40+
41+
impl<S: CheapCloneStr> NamedLineResolver<S> {
42+
pub(crate) fn new(area_styles: Option<impl Borrow<[GridTemplateArea<S>]>>) -> Self {
43+
let mut area_column_count = 0;
44+
let mut area_row_count = 0;
45+
let mut areas: HashMap<StrHasher<_>, GridTemplateArea<_>> = HashMap::new();
46+
if let Some(area_iter) = area_styles {
47+
for area in area_iter.borrow() {
48+
// TODO: Investigate eliminating clones
49+
areas.insert(StrHasher(area.name.clone()), area.clone());
50+
51+
area_column_count = area_column_count.max(area.column_end);
52+
area_row_count = area_row_count.max(area.row_end);
53+
}
54+
}
55+
56+
Self { area_column_count, area_row_count, areas, lines: HashMap::new() }
57+
}
58+
59+
#[inline(always)]
60+
pub(crate) fn resolve_row_names(&self, line: &Line<GridPlacement<S>>) -> Line<NonNamedGridPlacement> {
61+
self.resolve_line_names(line, GridAreaAxis::Row)
62+
}
63+
64+
#[inline(always)]
65+
pub(crate) fn resolve_column_names(&self, line: &Line<GridPlacement<S>>) -> Line<NonNamedGridPlacement> {
66+
self.resolve_line_names(line, GridAreaAxis::Column)
67+
}
68+
69+
#[inline(always)]
70+
pub(crate) fn resolve_line_names(
71+
&self,
72+
line: &Line<GridPlacement<S>>,
73+
axis: GridAreaAxis,
74+
) -> Line<NonNamedGridPlacement> {
75+
Line {
76+
start: self.resolve_line_name(&line.start, axis, GridAreaEnd::Start),
77+
end: self.resolve_line_name(&line.end, axis, GridAreaEnd::End),
78+
}
79+
}
80+
81+
pub(crate) fn resolve_line_name(
82+
&self,
83+
placement: &GridPlacement<S>,
84+
axis: GridAreaAxis,
85+
end: GridAreaEnd,
86+
) -> NonNamedGridPlacement {
87+
match placement {
88+
GridPlacement::Auto => NonNamedGridPlacement::Auto,
89+
GridPlacement::Line(grid_line) => NonNamedGridPlacement::Line(*grid_line),
90+
GridPlacement::Span(span) => NonNamedGridPlacement::Span(*span),
91+
GridPlacement::Named(name) => {
92+
let name = name.as_ref();
93+
if name.ends_with("-start") {
94+
let area_name = &name[0..(name.len() - 6)];
95+
if let Some(area) = self.areas.get(area_name) {
96+
return GenericGridPlacement::Line(area.get_side(axis, GridAreaEnd::Start));
97+
}
98+
} else if name.ends_with("-end") {
99+
let area_name = &name[0..(name.len() - 6)];
100+
if let Some(area) = self.areas.get(area_name) {
101+
return GenericGridPlacement::Line(area.get_side(axis, GridAreaEnd::End));
102+
}
103+
} else {
104+
if let Some(area) = self.areas.get(name) {
105+
return GenericGridPlacement::Line(area.get_side(axis, end));
106+
}
107+
}
108+
109+
// TODO: lookup names lines
110+
NonNamedGridPlacement::Auto
111+
}
112+
}
113+
}
114+
115+
pub(crate) fn area_column_count(&self) -> u16 {
116+
self.area_column_count
117+
}
118+
119+
pub(crate) fn area_row_count(&self) -> u16 {
120+
self.area_row_count
121+
}
122+
}

0 commit comments

Comments
 (0)