diff --git a/crates/grida-canvas/src/htmlcss/collect.rs b/crates/grida-canvas/src/htmlcss/collect.rs index cb29cea2a..723e1d3c5 100644 --- a/crates/grida-canvas/src/htmlcss/collect.rs +++ b/crates/grida-canvas/src/htmlcss/collect.rs @@ -432,8 +432,16 @@ fn collect_element_with_counter( // Widgets with intrinsic sizes need their own Taffy node // for sizing to work — don't flatten them into inline groups. - let is_inline = child.display == types::Display::Inline - || child.display == types::Display::InlineBlock; + // Same for inline-block with explicit sizing: its width/height + // would be lost inside the inline path. Layout later emulates + // inline-block flow by mapping the parent to Taffy flex-wrap + // when all of its element children are inline-block. + let inline_block_with_size = child.display == types::Display::InlineBlock + && (child.width != types::CssLength::Auto + || child.height != types::CssLength::Auto); + let is_inline = (child.display == types::Display::Inline + || child.display == types::Display::InlineBlock) + && !inline_block_with_size; if is_inline && !child.widget.is_widget() && child.replaced.is_none() { collect_inline_items(&child, &mut pending_inline); } else { diff --git a/crates/grida-canvas/src/htmlcss/layout.rs b/crates/grida-canvas/src/htmlcss/layout.rs index 7c03e12a3..c99967c9a 100644 --- a/crates/grida-canvas/src/htmlcss/layout.rs +++ b/crates/grida-canvas/src/htmlcss/layout.rs @@ -126,6 +126,19 @@ fn build_taffy_node( apply_replaced_intrinsic_size(&mut style, replaced, images); } + // Emulate inline-block sibling flow via Taffy flex-wrap. Taffy has no + // inline formatting context, so a block container holding only + // inline-block siblings would otherwise stack them vertically. Only + // apply when ≥2 inline-block element children exist and no text or + // non-inline-block elements would be misrouted through flex. + if style.display == taffy::Display::Block && should_emulate_inline_block_container(el) { + style.display = taffy::Display::Flex; + style.flex_wrap = taffy::FlexWrap::Wrap; + // Override default `stretch` so inline-blocks keep their + // own block-size instead of filling the container's line height. + style.align_items = Some(taffy::AlignItems::Start); + } + // Build child nodes let mut child_ids: Vec = Vec::new(); @@ -176,6 +189,26 @@ fn build_taffy_node( taffy.new_with_children(style, &child_ids).unwrap() } +/// Returns true when `el` should lay out its children as a horizontal +/// flex-wrap row to emulate inline-block flow. Only safe when the +/// container holds ≥2 inline-block element siblings and no text or +/// non-inline-block element children (those would require a real inline +/// formatting context to mix with inline-blocks correctly). +fn should_emulate_inline_block_container(el: &StyledElement) -> bool { + let mut inline_block_count = 0usize; + for child in &el.children { + match child { + StyledNode::Element(child_el) => match child_el.display { + types::Display::InlineBlock => inline_block_count += 1, + types::Display::None => {} + _ => return false, + }, + StyledNode::Text(_) | StyledNode::InlineGroup(_) => return false, + } + } + inline_block_count >= 2 +} + /// Taffy context for text/inline leaf nodes. Stores inline items so the /// measure function can build a Skia Paragraph with placeholders at any /// available width. diff --git a/fixtures/test-html/L0/layout-display-inline-block.html b/fixtures/test-html/L0/layout-display-inline-block.html new file mode 100644 index 000000000..7bb679ed5 --- /dev/null +++ b/fixtures/test-html/L0/layout-display-inline-block.html @@ -0,0 +1,51 @@ + + + + + Layout: display: inline-block + + + +
+
+
+
+
+
+ + diff --git a/fixtures/test-html/suites/L0.exact.json b/fixtures/test-html/suites/L0.exact.json index 2e21f5434..5716626e4 100644 --- a/fixtures/test-html/suites/L0.exact.json +++ b/fixtures/test-html/suites/L0.exact.json @@ -85,6 +85,7 @@ { "path": "../L0/paint-border-style-dashed.html" }, { "path": "../L0/paint-filter-drop-shadow.html" }, { "path": "../L0/paint-transform-matrix.html" }, - { "path": "../L0/paint-filter-blur.html" } + { "path": "../L0/paint-filter-blur.html" }, + { "path": "../L0/layout-display-inline-block.html" } ] }