diff --git a/Tests/LibWeb/Ref/box-with-transform-should-be-above-other-boxes.html b/Tests/LibWeb/Ref/box-with-transform-should-be-above-other-boxes.html new file mode 100644 index 00000000000..4ec10cf72a2 --- /dev/null +++ b/Tests/LibWeb/Ref/box-with-transform-should-be-above-other-boxes.html @@ -0,0 +1,19 @@ + + +
diff --git a/Tests/LibWeb/Ref/reference/box-with-transform-should-be-above-other-boxes-ref.html b/Tests/LibWeb/Ref/reference/box-with-transform-should-be-above-other-boxes-ref.html new file mode 100644 index 00000000000..c5379e0454b --- /dev/null +++ b/Tests/LibWeb/Ref/reference/box-with-transform-should-be-above-other-boxes-ref.html @@ -0,0 +1,10 @@ + +
diff --git a/Userland/Libraries/LibWeb/Painting/StackingContext.cpp b/Userland/Libraries/LibWeb/Painting/StackingContext.cpp index bd199ac98d0..b8f43c67e65 100644 --- a/Userland/Libraries/LibWeb/Painting/StackingContext.cpp +++ b/Userland/Libraries/LibWeb/Painting/StackingContext.cpp @@ -133,20 +133,11 @@ void StackingContext::paint_descendants(PaintContext& context, Paintable const& return IterationDecision::Continue; } - if (stacking_context && z_index.value_or(0) != 0) + if (stacking_context) return IterationDecision::Continue; if (child.is_positioned() && z_index.value_or(0) == 0) return IterationDecision::Continue; - if (stacking_context) { - // FIXME: This may not be fully correct with respect to the paint phases. - if (phase == StackingContextPaintPhase::Foreground) { - paint_child(context, *stacking_context); - } - // Note: Don't further recurse into descendants as paint_child() will do that. - return IterationDecision::Continue; - } - bool child_is_inline_or_replaced = child.is_inline() || is(child.layout_node()); switch (phase) { case StackingContextPaintPhase::BackgroundAndBorders: @@ -223,7 +214,9 @@ void StackingContext::paint_internal(PaintContext& context) const // Stacking contexts formed by positioned descendants with negative z-indices (excluding 0) in z-index order // (most negative first) then tree order. (step 3) - // NOTE: This doesn't check if a descendant is positioned as modern CSS allows for alternative methods to establish stacking contexts. + // Here, we treat non-positioned stacking contexts as if they were positioned, because CSS 2.0 spec does not + // account for new properties like `transform` and `opacity` that can create stacking contexts. + // https://github.com/w3c/csswg-drafts/issues/2717 for (auto* child : m_children) { if (child->paintable().computed_values().z_index().has_value() && child->paintable().computed_values().z_index().value() < 0) paint_child(context, *child); @@ -239,11 +232,10 @@ void StackingContext::paint_internal(PaintContext& context) const paint_descendants(context, paintable(), StackingContextPaintPhase::Foreground); // Draw positioned descendants with z-index `0` or `auto` in tree order. (step 8) - // FIXME: There's more to this step that we have yet to understand and implement. - for (auto const& paintable : m_positioned_descendants_with_stack_level_0_and_stacking_contexts) { - if (!paintable->is_positioned()) - continue; - + // Here, we treat non-positioned stacking contexts as if they were positioned, because CSS 2.0 spec does not + // account for new properties like `transform` and `opacity` that can create stacking contexts. + // https://github.com/w3c/csswg-drafts/issues/2717 + for (auto const& paintable : m_positioned_descendants_and_stacking_contexts_with_stack_level_0) { // At this point, `paintable_box` is a positioned descendant with z-index: auto. // FIXME: This is basically duplicating logic found elsewhere in this same function. Find a way to make this more elegant. auto* parent_paintable = paintable->parent(); @@ -260,7 +252,9 @@ void StackingContext::paint_internal(PaintContext& context) const // Stacking contexts formed by positioned descendants with z-indices greater than or equal to 1 in z-index order // (smallest first) then tree order. (Step 9) - // NOTE: This doesn't check if a descendant is positioned as modern CSS allows for alternative methods to establish stacking contexts. + // Here, we treat non-positioned stacking contexts as if they were positioned, because CSS 2.0 spec does not + // account for new properties like `transform` and `opacity` that can create stacking contexts. + // https://github.com/w3c/csswg-drafts/issues/2717 for (auto* child : m_children) { if (child->paintable().computed_values().z_index().has_value() && child->paintable().computed_values().z_index().value() >= 1) paint_child(context, *child); @@ -393,7 +387,7 @@ TraversalDecision StackingContext::hit_test(CSSPixelPoint position, HitTestType } // 6. the child stacking contexts with stack level 0 and the positioned descendants with stack level 0. - for (auto const& paintable : m_positioned_descendants_with_stack_level_0_and_stacking_contexts.in_reverse()) { + for (auto const& paintable : m_positioned_descendants_and_stacking_contexts_with_stack_level_0.in_reverse()) { if (paintable->stacking_context()) { if (paintable->stacking_context()->hit_test(transformed_position, type, callback) == TraversalDecision::Break) return TraversalDecision::Break; diff --git a/Userland/Libraries/LibWeb/Painting/StackingContext.h b/Userland/Libraries/LibWeb/Painting/StackingContext.h index 8fb9ecb6e88..1801f16f164 100644 --- a/Userland/Libraries/LibWeb/Painting/StackingContext.h +++ b/Userland/Libraries/LibWeb/Painting/StackingContext.h @@ -56,7 +56,7 @@ private: size_t m_index_in_tree_order { 0 }; Optional m_last_paint_generation_id; - Vector> m_positioned_descendants_with_stack_level_0_and_stacking_contexts; + Vector> m_positioned_descendants_and_stacking_contexts_with_stack_level_0; Vector> m_non_positioned_floating_descendants; static void paint_child(PaintContext&, StackingContext const&); diff --git a/Userland/Libraries/LibWeb/Painting/ViewportPaintable.cpp b/Userland/Libraries/LibWeb/Painting/ViewportPaintable.cpp index b0ff83d16a7..2d0f6cfb4be 100644 --- a/Userland/Libraries/LibWeb/Painting/ViewportPaintable.cpp +++ b/Userland/Libraries/LibWeb/Painting/ViewportPaintable.cpp @@ -43,7 +43,7 @@ void ViewportPaintable::build_stacking_context_tree() auto* parent_context = const_cast(paintable).enclosing_stacking_context(); auto establishes_stacking_context = paintable.layout_node().establishes_stacking_context(); if ((paintable.is_positioned() || establishes_stacking_context) && paintable.computed_values().z_index().value_or(0) == 0) - parent_context->m_positioned_descendants_with_stack_level_0_and_stacking_contexts.append(paintable); + parent_context->m_positioned_descendants_and_stacking_contexts_with_stack_level_0.append(paintable); if (!paintable.is_positioned() && paintable.is_floating()) parent_context->m_non_positioned_floating_descendants.append(paintable); if (!establishes_stacking_context) {