Skip to content

Commit 8ad6109

Browse files
committed
feat: update grid track impl
1 parent 50bc301 commit 8ad6109

4 files changed

Lines changed: 526 additions & 45 deletions

File tree

float-pigment-layout/docs/grid-zh_CN.md

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ float-pigment-layout/src/algo/grid/
1616
├── mod.rs # 主入口,Grid 布局算法实现
1717
├── alignment.rs # 对齐计算 (align/justify-items/self/content)
1818
├── track_size.rs # 轨道尺寸计算 (fr, auto, fixed)
19+
├── track.rs # 轨道数据结构 (GridTrack, GridTracks)
1920
├── placement.rs # Grid 项目放置算法
2021
├── matrix.rs # Grid 矩阵数据结构
2122
├── grid_item.rs # Grid 项目结构定义
@@ -56,18 +57,18 @@ float-pigment-layout/src/algo/grid/
5657
| +-- 使用动态网格 (DynamicGrid) 单次遍历放置项目 |
5758
| +-- 支持 grid-auto-flow: row / column (dense 未实现) |
5859
| |
59-
| 5. Track Sizing (§11.3) |
60-
| +-- 初始化轨道尺寸 (简化版,无 growth limit) |
60+
| 5. Track Sizing (§11.3-11.4) |
61+
| +-- 初始化轨道 base_size 和 growth_limit (§11.4) |
6162
| +-- §11.7 Flex Tracks: 计算 fr 单位的实际像素值 |
6263
| +-- 先计算列尺寸,再计算行尺寸 |
6364
| |
6465
| 6. Item Sizing (§11.5) |
6566
| +-- 计算每个项目的 min-content / max-content contribution |
6667
| +-- 使用 outer size (margin-box) 参与 track sizing |
6768
| |
68-
| 7. Finalize Tracks (§11.5) |
69-
| +-- 根据项目 outer size 调整 auto 轨道尺寸 |
70-
| +-- (§11.6 Maximize Tracks 未独立实现) |
69+
| 7. Finalize Tracks (§11.5-11.6) |
70+
| +-- 根据项目 outer size 调整 auto 轨道尺寸 (§11.5) |
71+
| +-- §11.6 Maximize Tracks: 分配 free space 给 auto tracks |
7172
| |
7273
| 8. Content Distribution (§10.5) |
7374
| +-- 应用 align-content: 分配 block axis 方向的剩余空间 |
@@ -81,8 +82,6 @@ float-pigment-layout/src/algo/grid/
8182
| [!] LIMITATIONS vs W3C Specification: |
8283
| - §11.1 Step 3-4: iterative re-resolution NOT implemented |
8384
| - §8.5: dense packing mode NOT implemented |
84-
| - §11.4: base size / growth limit NOT separately maintained |
85-
| - §11.6: Maximize Tracks NOT implemented (free space not distributed) |
8685
+-----------------------------------------------------------------------------------+
8786
```
8887

@@ -133,14 +132,14 @@ float-pigment-layout/src/algo/grid/
133132

134133
计算每个 track 的 used track size,先 columns 后 rows:
135134

136-
1. **Fixed sizing function**:直接使用解析后的像素值
137-
2. **Flexible sizing function (`fr`)**
135+
1. **初始化 (§11.4)**:为每个 track 初始化 `base_size``growth_limit`
136+
- Fixed sizing function:`base_size` = 解析后的像素值
137+
- Flexible sizing function (`fr`):`base_size` = 0,`growth_limit` = infinity
138+
- `auto` sizing function:`base_size` = 0,`growth_limit` = infinity
139+
2. **Flexible tracks (§11.7)**
138140
- 计算 free space:`free_space = available - fixed_tracks - gutters`
139141
- 计算 hypothetical fr size:`fr_size = free_space / total_fr`
140142
- Used track size:`track_size = fr_value × fr_size`
141-
3. **`auto` sizing function**:初始化为 0,待 Step 7 根据 content contribution 调整
142-
143-
> ⚠️ 简化实现:未分别维护 W3C §11.4 规定的 `base size``growth limit`
144143

145144
##### Step 6: Item Sizing
146145

@@ -155,12 +154,15 @@ float-pigment-layout/src/algo/grid/
155154

156155
根据 item contribution 调整 auto track size:
157156

158-
1. 遍历所有 `auto` tracks
159-
2. 取该 track 内所有 items 的最大 outer size (margin-box)
160-
3. 更新 track size
161-
4. 输出:最终的 `each_inline_size[]``each_block_size[]`
162-
163-
> ⚠️ 简化实现:W3C §11.6 "Maximize Tracks" 未作为独立步骤实现
157+
1. **§11.5 Resolve Intrinsic Track Sizes**
158+
- 遍历所有 `auto` tracks
159+
- 取该 track 内所有 items 的最大 outer size (margin-box)
160+
- 更新 track `base_size`
161+
2. **§11.6 Maximize Tracks**
162+
- 仅当 container 有 definite size 时执行
163+
- 计算 free space:`free_space = container_size - total_base_size - gutters`
164+
- 将 free space 平均分配给 `growth_limit` 为 infinity 的 tracks (auto tracks)
165+
3. 输出:最终的 `each_inline_size[]``each_block_size[]`
164166

165167
##### Step 8: Content Distribution
166168

float-pigment-layout/docs/grid.md

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ float-pigment-layout/src/algo/grid/
1616
├── mod.rs # Main entry, Grid layout algorithm implementation
1717
├── alignment.rs # Alignment calculations (align/justify-items/self/content)
1818
├── track_size.rs # Track sizing calculations (fr, auto, fixed)
19+
├── track.rs # Track data structures (GridTrack, GridTracks)
1920
├── placement.rs # Grid item placement algorithm
2021
├── matrix.rs # Grid matrix data structure
2122
├── grid_item.rs # Grid item structure definitions
@@ -56,18 +57,18 @@ This implementation uses a simplified single-pass approach with 9 steps:
5657
| +-- Single-pass placement using DynamicGrid |
5758
| +-- Support grid-auto-flow: row / column (dense NOT implemented) |
5859
| |
59-
| 5. Track Sizing (§11.3) |
60-
| +-- Initialize track sizes (simplified, no growth limit) |
60+
| 5. Track Sizing (§11.3-11.4) |
61+
| +-- Initialize track base_size and growth_limit (§11.4) |
6162
| +-- §11.7 Flex Tracks: Calculate fr unit pixel values |
6263
| +-- Size columns first, then rows |
6364
| |
6465
| 6. Item Sizing (§11.5) |
6566
| +-- Calculate min-content / max-content contribution for each item |
6667
| +-- Use outer size (margin-box) for track sizing |
6768
| |
68-
| 7. Finalize Tracks (§11.5) |
69-
| +-- Adjust auto track sizes based on item outer size |
70-
| +-- (§11.6 Maximize Tracks NOT implemented) |
69+
| 7. Finalize Tracks (§11.5-11.6) |
70+
| +-- Adjust auto track sizes based on item outer size (§11.5) |
71+
| +-- §11.6 Maximize Tracks: Distribute free space to auto tracks |
7172
| |
7273
| 8. Content Distribution (§10.5) |
7374
| +-- Apply align-content: distribute remaining space on block axis |
@@ -81,8 +82,6 @@ This implementation uses a simplified single-pass approach with 9 steps:
8182
| [!] LIMITATIONS vs W3C Specification: |
8283
| - §11.1 Step 3-4: iterative re-resolution NOT implemented |
8384
| - §8.5: dense packing mode NOT implemented |
84-
| - §11.4: base size / growth limit NOT separately maintained |
85-
| - §11.6: Maximize Tracks NOT implemented (free space not distributed) |
8685
+-----------------------------------------------------------------------------------+
8786
```
8887

@@ -133,14 +132,14 @@ Auto-place items into grid matrix according to `grid-auto-flow`:
133132

134133
Calculate used track size for each track, columns first then rows:
135134

136-
1. **Fixed sizing function**: Use resolved pixel values directly
137-
2. **Flexible sizing function (`fr`)**:
135+
1. **Initialize (§11.4)**: Initialize `base_size` and `growth_limit` for each track
136+
- Fixed sizing function: `base_size` = resolved pixel value
137+
- Flexible sizing function (`fr`): `base_size` = 0, `growth_limit` = infinity
138+
- `auto` sizing function: `base_size` = 0, `growth_limit` = infinity
139+
2. **Flexible tracks (§11.7)**:
138140
- Calculate free space: `free_space = available - fixed_tracks - gutters`
139141
- Calculate hypothetical fr size: `fr_size = free_space / total_fr`
140142
- Used track size: `track_size = fr_value × fr_size`
141-
3. **`auto` sizing function**: Initialize to 0, adjust in Step 7 based on content contribution
142-
143-
> ⚠️ Simplified: Does NOT separately maintain W3C §11.4 `base size` and `growth limit`
144143

145144
##### Step 6: Item Sizing
146145

@@ -155,12 +154,15 @@ Recursively calculate size contribution of each grid item:
155154

156155
Adjust auto track sizes based on item contribution:
157156

158-
1. Iterate through all `auto` tracks
159-
2. Take maximum outer size (margin-box) of all items spanning that track
160-
3. Update track size
161-
4. Output: Final `each_inline_size[]`, `each_block_size[]`
162-
163-
> ⚠️ Simplified: W3C §11.6 "Maximize Tracks" NOT separately implemented
157+
1. **§11.5 Resolve Intrinsic Track Sizes**:
158+
- Iterate through all `auto` tracks
159+
- Take maximum outer size (margin-box) of all items spanning that track
160+
- Update track `base_size`
161+
2. **§11.6 Maximize Tracks**:
162+
- Only execute when container has definite size
163+
- Calculate free space: `free_space = container_size - total_base_size - gutters`
164+
- Distribute free space equally to tracks with `growth_limit` = infinity (auto tracks)
165+
3. Output: Final `each_inline_size[]`, `each_block_size[]`
164166

165167
##### Step 8: Content Distribution
166168

float-pigment-layout/src/algo/grid/mod.rs

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ mod dynamic_grid;
5656
mod grid_item;
5757
mod matrix;
5858
mod placement;
59+
mod track;
5960
mod track_size;
6061

6162
use crate::{
@@ -396,12 +397,58 @@ impl<T: LayoutTreeNode> GridContainer<T> for LayoutUnit<T> {
396397
// Adjust track sizes based on item content:
397398
// - For auto tracks: size to fit content (using outer/margin-box size)
398399
// - For fixed tracks: use the specified size
399-
//
400-
// NOTE: §11.6 Maximize Tracks (distributing free space) NOT implemented.
401400
// ═══════════════════════════════════════════════════════════════════════
402-
let (each_inline_size, each_block_size) =
401+
let (column_result, row_result) =
403402
compute_track_sizes(&mut grid_layout_matrix, should_use_min_content_size);
404403

404+
// ═══════════════════════════════════════════════════════════════════════
405+
// STEP 7b: Maximize Tracks (§11.6)
406+
// CSS Grid §11.6: https://www.w3.org/TR/css-grid-1/#algo-grow-tracks
407+
//
408+
// If free space is positive, distribute it equally to tracks with
409+
// infinite growth limits (auto tracks).
410+
//
411+
// NOTE: Only apply when container has definite size in relevant axis.
412+
// ═══════════════════════════════════════════════════════════════════════
413+
use crate::algo::grid::track::GridTracks;
414+
415+
let mut column_tracks: GridTracks<T> =
416+
GridTracks::from_sizes(&column_result.sizes, &column_result.has_explicit);
417+
let mut row_tracks: GridTracks<T> =
418+
GridTracks::from_sizes(&row_result.sizes, &row_result.has_explicit);
419+
420+
// Maximize column tracks only if container has definite width (not auto)
421+
let has_definite_width = !matches!(style.width(), DefLength::Auto);
422+
if has_definite_width {
423+
if let Some(container_width) = requested_inner_size.0.width.val() {
424+
let total_column_size = column_tracks.total_base_size();
425+
let free_space = container_width - total_column_size - total_column_gaps;
426+
column_tracks.maximize(free_space);
427+
}
428+
}
429+
430+
// Maximize row tracks only if container has definite height (not auto)
431+
let has_definite_height = !matches!(style.height(), DefLength::Auto);
432+
if has_definite_height {
433+
if let Some(container_height) = requested_inner_size.0.height.val() {
434+
let total_row_size = row_tracks.total_base_size();
435+
let free_space = container_height - total_row_size - total_row_gaps;
436+
row_tracks.maximize(free_space);
437+
}
438+
}
439+
440+
// Get final track sizes
441+
let each_inline_size = column_tracks.resolved_sizes();
442+
let each_block_size = row_tracks.resolved_sizes();
443+
444+
// Update items with maximized track sizes
445+
for item in grid_layout_matrix.items_mut() {
446+
let row = item.row();
447+
let column = item.column();
448+
item.track_size.width = OptionNum::some(each_inline_size[column]);
449+
item.track_size.height = OptionNum::some(each_block_size[row]);
450+
}
451+
405452
let total_inline_size: T::Length = each_inline_size
406453
.iter()
407454
.fold(T::Length::zero(), |acc, cur| acc + *cur)
@@ -612,20 +659,24 @@ fn initialize_track_list<'a, T: LayoutTreeNode>(
612659
}
613660
}
614661

615-
/// Compute final track sizes based on item content.
662+
/// Track sizing result containing sizes and explicit flags.
663+
struct TrackSizingResult<T: LayoutTreeNode> {
664+
sizes: Vec<T::Length>,
665+
has_explicit: Vec<bool>,
666+
}
667+
668+
/// Compute track sizes based on item content.
616669
///
617670
/// CSS Grid §11.5: https://www.w3.org/TR/css-grid-1/#algo-content
618671
///
619672
/// - For explicit tracks: use the specified size (at least min-content)
620673
/// - For auto tracks: use the item's outer size (margin box)
621674
///
622-
/// NOTE: §11.6 Maximize Tracks (distributing free space to tracks) NOT implemented.
623-
///
624-
/// Returns (column_sizes, row_sizes).
675+
/// Returns (column_result, row_result).
625676
fn compute_track_sizes<T: LayoutTreeNode>(
626677
grid_layout_matrix: &mut GridLayoutMatrix<T>,
627678
should_use_min_content_size: bool,
628-
) -> (Vec<T::Length>, Vec<T::Length>) {
679+
) -> (TrackSizingResult<T>, TrackSizingResult<T>) {
629680
let row_count = grid_layout_matrix.row_count();
630681
let column_count = grid_layout_matrix.column_count();
631682

@@ -710,5 +761,14 @@ fn compute_track_sizes<T: LayoutTreeNode>(
710761
item.track_size.height = OptionNum::some(row_sizes[row]);
711762
}
712763

713-
(column_sizes, row_sizes)
764+
(
765+
TrackSizingResult {
766+
sizes: column_sizes,
767+
has_explicit: column_has_explicit,
768+
},
769+
TrackSizingResult {
770+
sizes: row_sizes,
771+
has_explicit: row_has_explicit,
772+
},
773+
)
714774
}

0 commit comments

Comments
 (0)