mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-28 11:49:44 +00:00
LibWeb: Allow <svg>
to establish a stacking context
83b6bc4
went too far by forbidding SVGSVGElement from establishing a
stacking context. This element type does follow the behavior of CSS
boxes, unlike inner SVG elements like `<rect>`, `<circle>`, etc., which
are not supposed to be aware of concepts like stacking contexts,
overflow clipping, scroll offsets, etc.
This change allows us to delete overrides of `before_paint()` and
`after_paint()` in SVGPaintable and SVGSVGPaintable, because display
list recording code has been rearranged to take care of clipping and
scrolling before recursing into SVGSVGPaintable descendants.
`Screenshot/images/css-transform-box-ref.png` expectation is updated and
fixes a bug where a rectangle at the very bottom of the page was not
clipped correctly.
`Screenshot/images/svg-filters-lb-website-ref.png` has a more subtle
difference, but if you look closely, you’ll see it matches other
browsers more closely now.
This commit is contained in:
parent
79293a3cbc
commit
910fd426a2
Notes:
github-actions[bot]
2025-07-12 09:02:17 +00:00
Author: https://github.com/kalenikaliaksandr
Commit: 910fd426a2
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5413
Reviewed-by: https://github.com/gmta ✅
10 changed files with 87 additions and 60 deletions
|
@ -108,9 +108,9 @@ void StackingContext::paint_svg(PaintContext& context, PaintableBox const& paint
|
|||
if (phase != PaintPhase::Foreground)
|
||||
return;
|
||||
|
||||
paintable.before_paint(context, PaintPhase::Foreground);
|
||||
paint_node(paintable, context, PaintPhase::Background);
|
||||
paint_node(paintable, context, PaintPhase::Border);
|
||||
paintable.before_paint(context, PaintPhase::Foreground);
|
||||
SVGSVGPaintable::paint_svg_box(context, paintable, phase);
|
||||
paintable.after_paint(context, PaintPhase::Foreground);
|
||||
}
|
||||
|
@ -118,14 +118,14 @@ void StackingContext::paint_svg(PaintContext& context, PaintableBox const& paint
|
|||
void StackingContext::paint_descendants(PaintContext& context, Paintable const& paintable, StackingContextPaintPhase phase)
|
||||
{
|
||||
paintable.for_each_child([&context, phase](auto& child) {
|
||||
if (child.has_stacking_context())
|
||||
return IterationDecision::Continue;
|
||||
|
||||
if (child.layout_node().is_svg_svg_box()) {
|
||||
paint_svg(context, static_cast<PaintableBox const&>(child), to_paint_phase(phase));
|
||||
return IterationDecision::Continue;
|
||||
}
|
||||
|
||||
if (child.has_stacking_context())
|
||||
return IterationDecision::Continue;
|
||||
|
||||
// NOTE: Grid specification https://www.w3.org/TR/css-grid-2/#z-order says that grid items should be treated
|
||||
// the same way as CSS2 defines for inline-blocks:
|
||||
// "For each one of these, treat the element as if it created a new stacking context, but any positioned
|
||||
|
@ -199,10 +199,7 @@ void StackingContext::paint_descendants(PaintContext& context, Paintable const&
|
|||
void StackingContext::paint_child(PaintContext& context, StackingContext const& child)
|
||||
{
|
||||
VERIFY(!child.paintable_box().layout_node().is_svg_box());
|
||||
VERIFY(!child.paintable_box().layout_node().is_svg_svg_box());
|
||||
|
||||
const_cast<StackingContext&>(child).set_last_paint_generation_id(context.paint_generation_id());
|
||||
|
||||
child.paint(context);
|
||||
}
|
||||
|
||||
|
@ -210,10 +207,27 @@ void StackingContext::paint_internal(PaintContext& context) const
|
|||
{
|
||||
VERIFY(!paintable_box().layout_node().is_svg_box());
|
||||
if (paintable_box().layout_node().is_svg_svg_box()) {
|
||||
paint_svg(context, paintable_box(), PaintPhase::Foreground);
|
||||
auto const& svg_svg_paintable = static_cast<SVGSVGPaintable const&>(paintable_box());
|
||||
paint_node(svg_svg_paintable, context, PaintPhase::Background);
|
||||
paint_node(svg_svg_paintable, context, PaintPhase::Border);
|
||||
|
||||
svg_svg_paintable.before_paint(context, PaintPhase::Foreground);
|
||||
SVGSVGPaintable::paint_descendants(context, svg_svg_paintable, PaintPhase::Foreground);
|
||||
svg_svg_paintable.after_paint(context, PaintPhase::Foreground);
|
||||
|
||||
paint_node(svg_svg_paintable, context, PaintPhase::Outline);
|
||||
if (context.should_paint_overlay()) {
|
||||
paint_node(svg_svg_paintable, context, PaintPhase::Overlay);
|
||||
paint_descendants(context, svg_svg_paintable, StackingContextPaintPhase::FocusAndOverlay);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
context.display_list_recorder().push_scroll_frame_id({});
|
||||
ScopeGuard restore_scroll_frame_id([&] {
|
||||
context.display_list_recorder().pop_scroll_frame_id();
|
||||
});
|
||||
|
||||
// For a more elaborate description of the algorithm, see CSS 2.1 Appendix E
|
||||
// Draw the background and borders for the context root (steps 1, 2)
|
||||
paint_node(paintable_box(), context, PaintPhase::Background);
|
||||
|
@ -357,9 +371,7 @@ void StackingContext::paint(PaintContext& context) const
|
|||
}
|
||||
}
|
||||
|
||||
context.display_list_recorder().push_scroll_frame_id({});
|
||||
paint_internal(context);
|
||||
context.display_list_recorder().pop_scroll_frame_id();
|
||||
|
||||
if (filter.has_value()) {
|
||||
context.display_list_recorder().restore();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue