Skip to content

Resolve grid areas for out-of-flow boxes at positioning time - #1143

Closed
nicoburns wants to merge 4 commits into
devin/1787348650-oof-hoistingfrom
devin/1787402661-oof-grid-area
Closed

Resolve grid areas for out-of-flow boxes at positioning time#1143
nicoburns wants to merge 4 commits into
devin/1787348650-oof-hoistingfrom
devin/1787402661-oof-grid-area

Conversation

@nicoburns

@nicoburns nicoburns commented Aug 22, 2026

Copy link
Copy Markdown
Member

Objective

Third PR in the out-of-flow hoisting series (stacked on #1141, which is stacked on #1140).

Per CSS, an absolutely positioned box whose containing block is generated by a grid container is positioned relative to the grid area determined by its grid-placement properties (falling back to the padding box for auto placement). With hoisting (#1141) the containing block may not be the box's parent, so grid areas must be resolved at final positioning time from the containing block's track geometry — this is also how Blink does it (OutOfFlowLayoutPartComputeOutOfFlowItemContainingRect keyed off the containing block, using the grid's persisted GridLayoutData).

Chrome confirms this applies to non-direct descendants too: the new grid_absolute_hoisted_descendant_grid_area gentest fixture (an abspos box with grid-row/grid-column set whose parent is a static in-flow grid item, so its CB is the grid) resolves against the grid area in Chrome, and now in taffy.

Context

  • perform_oof_layout now takes the current node's id and, per claimed candidate, reads the node's detailed layout info; if it is DetailedLayoutInfo::Grid, the candidate's inset-resolution area becomes DetailedGridInfo::resolve_absolute_grid_area(child.grid_row(), child.grid_column(), ...) instead of the passed padding-box area:
let (area_size, area_offset) = match tree.get_detailed_layout_info(node_id) {
    DetailedLayoutInfo::Grid(grid_info) => {
        let grid_area = grid_info.resolve_absolute_grid_area(
            child_style.grid_row(), child_style.grid_column(), direction, area_rect);
        (size_of(grid_area), origin_of(grid_area))
    }
    _ => (area_size, area_offset),
};
  • New OofItemStyle: CoreStyle style trait with defaulted, grid-feature-gated grid_row/grid_column methods — grid placement is an item property read from the candidate at positioning time, so it lives on a dedicated OOF-item style trait rather than CoreStyle. GridItemStyle keeps its own copies for in-flow grid items.

  • New LayoutContainingBlock: LayoutPartialTree tree trait housing the containing-block-side OOF positioning requirements:

    • type OofItemStyle<'a> + required get_oof_item_style(NodeId) — the candidate's style.
    • defaulted get_detailed_layout_info(NodeId) -> &DetailedLayoutInfo<Self::CustomIdent> (default returns DetailedLayoutInfo::None, degrading to padding-box positioning for custom trees that don't implement it).

    All container algorithms (compute_block_layout, compute_flexbox_layout, compute_grid_layout, compute_root_layout) require this trait, since any container may be the containing block of hoisted boxes. (A follow-up could move perform_oof_layout dispatch out of the algorithms into the shared traversal layer, at which point this trait becomes a dispatcher-only bound.)

  • DetailedLayoutInfo and the detailed grid info types are un-gated from the detailed_layout_info cargo feature (the feature is retained but no longer gates anything), so the data is available to the positioning pass in all builds. DetailedLayoutInfo becomes generic over the custom identifier string type (DetailedLayoutInfo<S = DefaultCheapStr>), with a hidden never-constructed variant consuming S when grid is disabled. Grid layout now always calls set_detailed_grid_info, and does so before its out-of-flow positioning pass so the pass can read the grid's own geometry.

  • Direct abspos children of a grid container that is itself their containing block are still laid out in-algorithm (unchanged); the positioning-time path handles hoisted (non-direct) descendants and root-claimed candidates.

  • New gentest fixtures: grid_absolute_hoisted_descendant_grid_area and grid_absolute_hoisted_descendant_auto_placement (8 generated tests, LTR/RTL × border-box/content-box). Full suite: 6013 gentests + hand-written tests pass; clippy clean; --no-default-features, --no-default-features --features grid, and --all-features all compile.

Feedback wanted

  • Whether the detailed_layout_info cargo feature should be removed outright now that it gates nothing.
  • The hidden Phantom variant on DetailedLayoutInfo (needed to consume the S generic when grid is disabled) — open to alternatives.

Link to Devin session: https://dioxus.staging.devinenterprise.com/sessions/65c5463061c8403bade7888271d5eeb4
Open in Devin Desktop: https://dioxus.staging.devinenterprise.com/desktop/session/65c5463061c8403bade7888271d5eeb4?variant=devin-insiders
Requested by: @nicoburns

@staging-devin-ai-integration

Copy link
Copy Markdown

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant