diff --git a/Userland/Libraries/LibWeb/Painting/Paintable.h b/Userland/Libraries/LibWeb/Painting/Paintable.h index 10269ed234..c784006646 100644 --- a/Userland/Libraries/LibWeb/Painting/Paintable.h +++ b/Userland/Libraries/LibWeb/Painting/Paintable.h @@ -88,6 +88,9 @@ public: virtual void before_children_paint(PaintContext&, PaintPhase) const { } virtual void after_children_paint(PaintContext&, PaintPhase) const { } + virtual void apply_clip_overflow_rect(PaintContext&, PaintPhase) const { } + virtual void clear_clip_overflow_rect(PaintContext&, PaintPhase) const { } + virtual Optional hit_test(CSSPixelPoint, HitTestType) const; virtual bool wants_mouse_events() const { return false; } diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp index f63cbd709f..a041696188 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -318,7 +318,7 @@ Optional PaintableBox::clip_rect() const return m_clip_rect; } -void PaintableBox::before_children_paint(PaintContext& context, PaintPhase phase) const +void PaintableBox::apply_clip_overflow_rect(PaintContext& context, PaintPhase phase) const { if (!AK::first_is_one_of(phase, PaintPhase::Background, PaintPhase::Border, PaintPhase::Foreground)) return; @@ -364,7 +364,7 @@ void PaintableBox::before_children_paint(PaintContext& context, PaintPhase phase } } -void PaintableBox::after_children_paint(PaintContext& context, PaintPhase phase) const +void PaintableBox::clear_clip_overflow_rect(PaintContext& context, PaintPhase phase) const { if (!AK::first_is_one_of(phase, PaintPhase::Background, PaintPhase::Border, PaintPhase::Foreground)) return; diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.h b/Userland/Libraries/LibWeb/Painting/PaintableBox.h index eb3b8125d5..d6477b20d4 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.h +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.h @@ -114,8 +114,8 @@ public: DOM::Document const& document() const { return layout_box().document(); } DOM::Document& document() { return layout_box().document(); } - virtual void before_children_paint(PaintContext&, PaintPhase) const override; - virtual void after_children_paint(PaintContext&, PaintPhase) const override; + virtual void apply_clip_overflow_rect(PaintContext&, PaintPhase) const override; + virtual void clear_clip_overflow_rect(PaintContext&, PaintPhase) const override; virtual Optional hit_test(CSSPixelPoint, HitTestType) const override; diff --git a/Userland/Libraries/LibWeb/Painting/StackingContext.cpp b/Userland/Libraries/LibWeb/Painting/StackingContext.cpp index 2b54e1e43b..f0d3859f04 100644 --- a/Userland/Libraries/LibWeb/Painting/StackingContext.cpp +++ b/Userland/Libraries/LibWeb/Painting/StackingContext.cpp @@ -71,8 +71,10 @@ static PaintPhase to_paint_phase(StackingContext::StackingContextPaintPhase phas void StackingContext::paint_descendants(PaintContext& context, Layout::Node const& box, StackingContextPaintPhase phase) const { - if (auto* paintable = box.paintable()) + if (auto* paintable = box.paintable()) { paintable->before_children_paint(context, to_paint_phase(phase)); + paintable->apply_clip_overflow_rect(context, to_paint_phase(phase)); + } box.for_each_child([&](auto& child) { // If `child` establishes its own stacking context, skip over it. @@ -124,8 +126,10 @@ void StackingContext::paint_descendants(PaintContext& context, Layout::Node cons } }); - if (auto* paintable = box.paintable()) + if (auto* paintable = box.paintable()) { + paintable->clear_clip_overflow_rect(context, to_paint_phase(phase)); paintable->after_children_paint(context, to_paint_phase(phase)); + } } void StackingContext::paint_internal(PaintContext& context) const @@ -137,12 +141,20 @@ void StackingContext::paint_internal(PaintContext& context) const auto paint_child = [&](auto* child) { auto parent = child->m_box.parent(); - auto* paintable = parent ? parent->paintable() : nullptr; - if (paintable) - paintable->before_children_paint(context, PaintPhase::Foreground); + auto* parent_paintable = parent ? parent->paintable() : nullptr; + if (parent_paintable) + parent_paintable->before_children_paint(context, PaintPhase::Foreground); + auto containing_block = child->m_box.containing_block(); + auto* containing_block_paintable = containing_block ? containing_block->paintable() : nullptr; + if (containing_block_paintable) + containing_block_paintable->apply_clip_overflow_rect(context, PaintPhase::Foreground); + child->paint(context); - if (paintable) - paintable->after_children_paint(context, PaintPhase::Foreground); + + if (parent_paintable) + parent_paintable->after_children_paint(context, PaintPhase::Foreground); + if (containing_block_paintable) + containing_block_paintable->clear_clip_overflow_rect(context, PaintPhase::Foreground); }; // Draw positioned descendants with negative z-indices (step 3) @@ -178,9 +190,13 @@ void StackingContext::paint_internal(PaintContext& context) const // but no stacking context of its own. // FIXME: This is basically duplicating logic found elsewhere in this same function. Find a way to make this more elegant. auto parent = paint_box.layout_node().parent(); - auto* paintable = parent ? parent->paintable() : nullptr; - if (paintable) - paintable->before_children_paint(context, PaintPhase::Foreground); + auto* parent_paintable = parent ? parent->paintable() : nullptr; + if (parent_paintable) + parent_paintable->before_children_paint(context, PaintPhase::Foreground); + auto containing_block = paint_box.layout_node().containing_block(); + auto* containing_block_paintable = containing_block ? containing_block->paintable() : nullptr; + if (containing_block_paintable) + containing_block_paintable->apply_clip_overflow_rect(context, PaintPhase::Foreground); paint_node(paint_box.layout_box(), context, PaintPhase::Background); paint_node(paint_box.layout_box(), context, PaintPhase::Border); paint_descendants(context, paint_box.layout_box(), StackingContextPaintPhase::BackgroundAndBorders); @@ -191,8 +207,10 @@ void StackingContext::paint_internal(PaintContext& context) const paint_node(paint_box.layout_box(), context, PaintPhase::FocusOutline); paint_node(paint_box.layout_box(), context, PaintPhase::Overlay); paint_descendants(context, paint_box.layout_box(), StackingContextPaintPhase::FocusAndOverlay); - if (paintable) - paintable->after_children_paint(context, PaintPhase::Foreground); + if (parent_paintable) + parent_paintable->after_children_paint(context, PaintPhase::Foreground); + if (containing_block_paintable) + containing_block_paintable->clear_clip_overflow_rect(context, PaintPhase::Foreground); return TraversalDecision::Continue; });