diff --git a/Libraries/LibWeb/Layout/TreeBuilder.cpp b/Libraries/LibWeb/Layout/TreeBuilder.cpp index 3b2bdc0c1a708..86d61836de697 100644 --- a/Libraries/LibWeb/Layout/TreeBuilder.cpp +++ b/Libraries/LibWeb/Layout/TreeBuilder.cpp @@ -925,6 +925,7 @@ RustFFI::FfiDomTreeBuilderCallbacks LayoutTreeBuildBridge::make_ffi_dom_tree_bui .layout_node_is_attached = existing_layout_node && existing_layout_node->parent(), .is_svg_container = node.is_svg_container(), .requires_svg_container = node.requires_svg_container(), + .is_svg_foreign_object = node.is_svg_foreign_object_element(), }; }, .request_top_layer_zone_rebuild = [](void* node_pointer) { VERIFY(node_pointer); diff --git a/Libraries/LibWeb/Rust/src/layout/block_formatting_context.rs b/Libraries/LibWeb/Rust/src/layout/block_formatting_context.rs index 35e32152daccc..315202ca2c756 100644 --- a/Libraries/LibWeb/Rust/src/layout/block_formatting_context.rs +++ b/Libraries/LibWeb/Rust/src/layout/block_formatting_context.rs @@ -2232,36 +2232,6 @@ impl<'pass> BlockFormattingContext<'pass> { } } - pub(crate) fn place_floats_after_run(&self) { - let floats = self.floats.borrow(); - for &floating_box in floats.iter() { - // SAFETY: Float records retain stable state-owned used-values pointers. - let used = floating_box.used_values; - let content_block_offset = - floating_box.top_margin_edge + used.margin_top.get() + used.border_box_top(false); - let inline_offset = if floating_box.side == FloatSide::Left { - // Left-side floats: offset_from_edge is from left edge (0) to left content edge of floating_box. - floating_box.offset_from_edge - } else { - // Right-side floats: offset_from_edge is from right edge (float_containing_block_inline_size) to the left content edge of floating_box. - let float_containing_block_inline_size = match used.inline_size_constraint.get() { - SizeConstraint::MinContent => CssPixels::default(), - // Preserve the MaxContent saturation quirk from the C++ fixed-point subtraction. - SizeConstraint::MaxContent => CssPixels::from_raw(i32::MAX), - SizeConstraint::None => floating_box.percentage_basis_inline_size.unwrap_or_default(), - }; - float_containing_block_inline_size - floating_box.offset_from_edge - }; - self.place_child( - floating_box.box_, - FfiCssPixelPoint { - x: inline_offset, - y: content_block_offset, - }, - ); - } - } - pub(crate) fn layout_interrupting_block_inside_inline_context( &self, run: &FormattingContextRun<'pass>, @@ -2516,6 +2486,25 @@ impl<'pass> BlockFormattingContext<'pass> { block_size: block_container_used.content_block_size.get(), }, ); + + let inline_offset = if side == FloatSide::Left { + floating_box.offset_from_edge + } else { + let float_containing_block_inline_size = match self.used(node).inline_size_constraint.get() { + SizeConstraint::MinContent => CssPixels::default(), + // Preserve the MaxContent saturation quirk from the C++ fixed-point subtraction. + SizeConstraint::MaxContent => CssPixels::from_raw(i32::MAX), + SizeConstraint::None => floating_box.percentage_basis_inline_size.unwrap_or_default(), + }; + float_containing_block_inline_size - floating_box.offset_from_edge + }; + self.place_child( + node, + FfiCssPixelPoint { + x: inline_offset, + y: content_block_offset, + }, + ); } fn layout_inline_children( diff --git a/Libraries/LibWeb/Rust/src/layout/formatting_context.rs b/Libraries/LibWeb/Rust/src/layout/formatting_context.rs index 5f81da5a901c4..866636d7c2674 100644 --- a/Libraries/LibWeb/Rust/src/layout/formatting_context.rs +++ b/Libraries/LibWeb/Rust/src/layout/formatting_context.rs @@ -1488,7 +1488,6 @@ fn run_formatting_context<'pass>( run.state.used_values(&run.callbacks, run.box_), context.derived_baselines_of_root_box(), ); - context.place_floats_after_run(); result } FormattingContextImplementation::Flex(context) => { @@ -1817,6 +1816,7 @@ pub unsafe extern "C" fn rust_layout_run_root_layout( if !first_child.is_invalid() && state.node_facts(&callbacks, first_child).is_svg_svg_box() { viewport_used.set_content_inline_size(viewport_inline_size); viewport_used.set_content_block_size(viewport_block_size); + place_child(&state, &callbacks, root, FfiCssPixelPoint::default()); state.create_used_values(&callbacks, first_child, root_constraints); root_for_layout = first_child; } @@ -1842,6 +1842,7 @@ pub unsafe extern "C" fn rust_layout_run_root_layout( input, None, ); + place_child(&state, &callbacks, root_for_layout, FfiCssPixelPoint::default()); run_abspos_layout_pass(state_ref, callbacks, should_collect_devtools_layout_data); state.commit_replacing(root, std::ptr::null_mut(), &callbacks, sink); }); @@ -1885,6 +1886,7 @@ pub unsafe extern "C" fn rust_layout_compute_subtree_layout( let viewport_used = state.create_used_values(&callbacks, viewport, viewport_constraints); viewport_used.set_content_inline_size(viewport_inline_size); viewport_used.set_content_block_size(viewport_block_size); + place_child(&state, &callbacks, viewport, FfiCssPixelPoint::default()); } let input = LayoutInput::new( AvailableSpace { diff --git a/Libraries/LibWeb/Rust/src/layout/inline_level_iterator.rs b/Libraries/LibWeb/Rust/src/layout/inline_level_iterator.rs index 0bf0999627438..6f11ac9417e9a 100644 --- a/Libraries/LibWeb/Rust/src/layout/inline_level_iterator.rs +++ b/Libraries/LibWeb/Rust/src/layout/inline_level_iterator.rs @@ -281,6 +281,7 @@ impl<'iterator, 'context, 'pass> InlineLevelIteratorGenerator<'iterator, 'contex let facts = self.context().facts(self.next_node); if facts.is_inline() && facts.has_box_model_metrics() + && !facts.is_break_node() && self.context().style(self.next_node).display().is_flow_inside() && !self.is_out_of_flow(self.next_node) && !facts.is_atomic_inline() diff --git a/Libraries/LibWeb/Rust/src/layout/tree_builder.rs b/Libraries/LibWeb/Rust/src/layout/tree_builder.rs index 8c731dd6242e8..f85861ecf1642 100644 --- a/Libraries/LibWeb/Rust/src/layout/tree_builder.rs +++ b/Libraries/LibWeb/Rust/src/layout/tree_builder.rs @@ -198,6 +198,7 @@ pub struct FfiPrincipalNodeEntryFacts { pub layout_node_is_attached: bool, pub is_svg_container: bool, pub requires_svg_container: bool, + pub is_svg_foreign_object: bool, } #[derive(Clone, Copy)] @@ -263,6 +264,7 @@ pub(crate) enum TopLayerEntryDecision { pub(crate) enum SvgEntryDecision { Continue, EnterSvgRoot, + EnterForeignContent, Skip, } @@ -556,6 +558,8 @@ pub(crate) fn principal_node_entry_decision( SvgEntryDecision::EnterSvgRoot } else if facts.requires_svg_container && !context.has_svg_root { SvgEntryDecision::Skip + } else if facts.is_svg_foreign_object { + SvgEntryDecision::EnterForeignContent } else { SvgEntryDecision::Continue }; @@ -895,6 +899,8 @@ fn update_svg_resource( prior_context_value: bool, ) { context.layout_svg_mask_or_clip_path = true; + let prior_has_svg_root = context.has_svg_root; + context.has_svg_root = true; state.ancestor_stack.push(layout_node); if !ancestor_stack_contains_element_layout_node(host, state, resource) { @@ -906,6 +912,7 @@ fn update_svg_resource( } assert!(state.ancestor_stack.pop().is_some()); + context.has_svg_root = prior_has_svg_root; context.layout_svg_mask_or_clip_path = prior_context_value; } @@ -1348,8 +1355,10 @@ fn update_principal_node_after_entry( let dom_node = update.dom_node; let prior_has_svg_root = update.context.has_svg_root; - if entry_decision.svg == SvgEntryDecision::EnterSvgRoot { - update.context.has_svg_root = true; + match entry_decision.svg { + SvgEntryDecision::EnterSvgRoot => update.context.has_svg_root = true, + SvgEntryDecision::EnterForeignContent => update.context.has_svg_root = false, + SvgEntryDecision::Continue | SvgEntryDecision::Skip => {} } let (has_layout_node, handled_display_contents) = if entry_decision.svg == SvgEntryDecision::Skip { @@ -1504,7 +1513,10 @@ fn update_principal_node_after_entry( } } - if entry_decision.svg == SvgEntryDecision::EnterSvgRoot { + if matches!( + entry_decision.svg, + SvgEntryDecision::EnterSvgRoot | SvgEntryDecision::EnterForeignContent + ) { context.has_svg_root = prior_has_svg_root; } } @@ -3457,6 +3469,7 @@ mod tests { layout_node_is_attached: true, is_svg_container: false, requires_svg_container: false, + is_svg_foreign_object: false, }; let mut context = TreeBuilderContext::default(); let decision = principal_node_entry_decision(facts, &context); @@ -3480,6 +3493,15 @@ mod tests { let decision = principal_node_entry_decision(facts, &context); assert!(decision.should_create_layout_node); assert_eq!(decision.svg, SvgEntryDecision::EnterSvgRoot); + + facts.is_svg_container = false; + facts.is_svg_foreign_object = true; + context.has_svg_root = true; + let decision = principal_node_entry_decision(facts, &context); + assert_eq!(decision.svg, SvgEntryDecision::EnterForeignContent); + context.has_svg_root = false; + let decision = principal_node_entry_decision(facts, &context); + assert_eq!(decision.svg, SvgEntryDecision::Skip); } #[test] diff --git a/Tests/LibWeb/Layout/expected/block-and-inline/atomic-inline-with-percentage-vertical-align.txt b/Tests/LibWeb/Layout/expected/block-and-inline/atomic-inline-with-percentage-vertical-align.txt index ed43881f5cf97..7992aa2515bd8 100644 --- a/Tests/LibWeb/Layout/expected/block-and-inline/atomic-inline-with-percentage-vertical-align.txt +++ b/Tests/LibWeb/Layout/expected/block-and-inline/atomic-inline-with-percentage-vertical-align.txt @@ -2,16 +2,16 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] [BFC] children BlockContainer at [1,1] [0+1+0 798 0+1+0] [0+1+0 62.8125 0+1+0] [BFC] children: not-inline BlockContainer
at [2,2] [0+1+0 796 0+1+0] [0+1+0 60.8125 0+1+0] children: inline frag 0 from BlockContainer start: 0, length: 0, rect: [3,3 30x30] baseline: 32 - frag 1 from BlockContainer start: 0, length: 0, rect: [4,35 30x30] baseline: 32 + frag 1 from BlockContainer start: 0, length: 0, rect: [3,35 30x30] baseline: 32 BlockContainer