diff --git a/Libraries/LibWeb/Painting/ClippableAndScrollable.cpp b/Libraries/LibWeb/Painting/ClippableAndScrollable.cpp index 5aec6b2e2fc..5587bfd79ac 100644 --- a/Libraries/LibWeb/Painting/ClippableAndScrollable.cpp +++ b/Libraries/LibWeb/Painting/ClippableAndScrollable.cpp @@ -38,11 +38,9 @@ Optional ClippableAndScrollable::clip_rect_for_hit_testing() const return {}; } -void ClippableAndScrollable::apply_clip(PaintContext& context) const +void ClippableAndScrollable::apply_clip(PaintContext& context, RefPtr from_clip_frame) const { - if (!m_enclosing_clip_frame) - return; - auto const& clip_rects = m_enclosing_clip_frame->clip_rects(); + auto const& clip_rects = from_clip_frame->clip_rects(); if (clip_rects.is_empty()) return; @@ -64,11 +62,9 @@ void ClippableAndScrollable::apply_clip(PaintContext& context) const } } -void ClippableAndScrollable::restore_clip(PaintContext& context) const +void ClippableAndScrollable::restore_clip(PaintContext& context, RefPtr from_clip_frame) const { - if (!m_enclosing_clip_frame) - return; - auto const& clip_rects = m_enclosing_clip_frame->clip_rects(); + auto const& clip_rects = from_clip_frame->clip_rects(); if (clip_rects.is_empty()) return; diff --git a/Libraries/LibWeb/Painting/ClippableAndScrollable.h b/Libraries/LibWeb/Painting/ClippableAndScrollable.h index d476c040202..dfd67a2b5de 100644 --- a/Libraries/LibWeb/Painting/ClippableAndScrollable.h +++ b/Libraries/LibWeb/Painting/ClippableAndScrollable.h @@ -16,7 +16,9 @@ public: virtual ~ClippableAndScrollable() = default; void set_enclosing_scroll_frame(RefPtr scroll_frame) { m_enclosing_scroll_frame = scroll_frame; } + void set_own_scroll_frame(RefPtr scroll_frame) { m_own_scroll_frame = scroll_frame; } void set_enclosing_clip_frame(RefPtr clip_frame) { m_enclosing_clip_frame = clip_frame; } + void set_own_clip_frame(RefPtr clip_frame) { m_own_clip_frame = clip_frame; } [[nodiscard]] RefPtr enclosing_scroll_frame() const { return m_enclosing_scroll_frame; } [[nodiscard]] Optional scroll_frame_id() const; @@ -31,10 +33,12 @@ public: return m_own_scroll_frame->own_offset(); return {}; } - void set_own_scroll_frame(RefPtr scroll_frame) { m_own_scroll_frame = scroll_frame; } - void apply_clip(PaintContext&) const; - void restore_clip(PaintContext&) const; + [[nodiscard]] RefPtr enclosing_clip_frame() const { return m_enclosing_clip_frame; } + [[nodiscard]] RefPtr own_clip_frame() const { return m_own_clip_frame; } + + void apply_clip(PaintContext&, RefPtr) const; + void restore_clip(PaintContext&, RefPtr) const; Gfx::AffineTransform const& combined_css_transform() const { return m_combined_css_transform; } void set_combined_css_transform(Gfx::AffineTransform const& transform) { m_combined_css_transform = transform; } @@ -43,6 +47,7 @@ private: RefPtr m_enclosing_scroll_frame; RefPtr m_own_scroll_frame; RefPtr m_enclosing_clip_frame; + RefPtr m_own_clip_frame; Gfx::AffineTransform m_combined_css_transform; }; diff --git a/Libraries/LibWeb/Painting/PaintableBox.cpp b/Libraries/LibWeb/Painting/PaintableBox.cpp index 8a5746a17b7..593a255c99b 100644 --- a/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -246,6 +246,13 @@ CSSPixelRect PaintableBox::absolute_border_box_rect() const return rect; } +// https://drafts.csswg.org/css-overflow-4/#overflow-clip-edge +CSSPixelRect PaintableBox::overflow_clip_edge_rect() const +{ + // FIXME: Apply overflow-clip-margin-* properties + return absolute_padding_box_rect(); +} + CSSPixelRect PaintableBox::absolute_paint_rect() const { if (!m_absolute_paint_rect.has_value()) @@ -623,18 +630,24 @@ void PaintableBox::reset_scroll_offset(PaintContext& context, PaintPhase) const void PaintableBox::apply_clip_overflow_rect(PaintContext& context, PaintPhase phase) const { + if (!enclosing_clip_frame()) + return; + if (!AK::first_is_one_of(phase, PaintPhase::Background, PaintPhase::Border, PaintPhase::TableCollapsedBorder, PaintPhase::Foreground, PaintPhase::Outline)) return; - apply_clip(context); + apply_clip(context, enclosing_clip_frame()); } void PaintableBox::clear_clip_overflow_rect(PaintContext& context, PaintPhase phase) const { + if (!enclosing_clip_frame()) + return; + if (!AK::first_is_one_of(phase, PaintPhase::Background, PaintPhase::Border, PaintPhase::TableCollapsedBorder, PaintPhase::Foreground, PaintPhase::Outline)) return; - restore_clip(context); + restore_clip(context, enclosing_clip_frame()); } void paint_cursor_if_needed(PaintContext& context, TextPaintable const& paintable, PaintableFragment const& fragment) @@ -847,32 +860,8 @@ void PaintableWithLines::paint(PaintContext& context, PaintPhase phase) const PaintableBox::paint(context, phase); - if (fragments().is_empty()) - return; - - bool should_clip_overflow = computed_values().overflow_x() != CSS::Overflow::Visible && computed_values().overflow_y() != CSS::Overflow::Visible; - - auto clip_box = absolute_padding_box_rect(); - if (get_clip_rect().has_value()) { - clip_box.intersect(get_clip_rect().value()); - should_clip_overflow = true; - } - if (should_clip_overflow) { - context.display_list_recorder().save(); - // FIXME: Handle overflow-x and overflow-y being different values. - context.display_list_recorder().add_clip_rect(context.rounded_device_rect(clip_box).to_type()); - - auto border_radii = normalized_border_radii_data(ShrinkRadiiForBorders::Yes); - CornerRadii corner_radii { - .top_left = border_radii.top_left.as_corner(context), - .top_right = border_radii.top_right.as_corner(context), - .bottom_right = border_radii.bottom_right.as_corner(context), - .bottom_left = border_radii.bottom_left.as_corner(context) - }; - if (corner_radii.has_any_radius()) { - context.display_list_recorder().add_rounded_rect_clip(corner_radii, context.rounded_device_rect(clip_box).to_type(), CornerClip::Outside); - } - + if (own_clip_frame()) { + apply_clip(context, own_clip_frame()); if (own_scroll_frame_id().has_value()) { context.display_list_recorder().push_scroll_frame_id(own_scroll_frame_id().value()); } @@ -900,12 +889,11 @@ void PaintableWithLines::paint(PaintContext& context, PaintPhase phase) const paint_text_fragment(context, static_cast(fragment.paintable()), fragment, phase); } - if (should_clip_overflow) { - context.display_list_recorder().restore(); - + if (own_clip_frame()) { if (own_scroll_frame_id().has_value()) { context.display_list_recorder().pop_scroll_frame_id(); } + restore_clip(context, own_clip_frame()); } } diff --git a/Libraries/LibWeb/Painting/PaintableBox.h b/Libraries/LibWeb/Painting/PaintableBox.h index db31fde5604..95e378c36f5 100644 --- a/Libraries/LibWeb/Painting/PaintableBox.h +++ b/Libraries/LibWeb/Painting/PaintableBox.h @@ -84,6 +84,7 @@ public: CSSPixelRect absolute_rect() const; CSSPixelRect absolute_padding_box_rect() const; CSSPixelRect absolute_border_box_rect() const; + CSSPixelRect overflow_clip_edge_rect() const; CSSPixelRect absolute_paint_rect() const; // These united versions of the above rects take continuation into account. diff --git a/Libraries/LibWeb/Painting/ViewportPaintable.cpp b/Libraries/LibWeb/Painting/ViewportPaintable.cpp index e87e9dbd06d..4bcf8f3ef81 100644 --- a/Libraries/LibWeb/Painting/ViewportPaintable.cpp +++ b/Libraries/LibWeb/Painting/ViewportPaintable.cpp @@ -136,6 +136,12 @@ void ViewportPaintable::assign_clip_frames() }); for_each_in_subtree([&](auto const& paintable) { + if (paintable.is_paintable_box()) { + auto const& paintable_box = static_cast(paintable); + if (auto clip_frame = clip_state.get(paintable_box); clip_frame.has_value()) { + const_cast(paintable_box).set_own_clip_frame(clip_frame.value()); + } + } for (auto block = paintable.containing_block(); !block->is_viewport(); block = block->containing_block()) { if (auto clip_frame = clip_state.get(block); clip_frame.has_value()) { if (paintable.is_paintable_box()) { diff --git a/Tests/LibWeb/Ref/expected/scrolled-text-with-clipped-corners-ref.html b/Tests/LibWeb/Ref/expected/scrolled-text-with-clipped-corners-ref.html index b3f0ad58095..867e30c8b50 100644 --- a/Tests/LibWeb/Ref/expected/scrolled-text-with-clipped-corners-ref.html +++ b/Tests/LibWeb/Ref/expected/scrolled-text-with-clipped-corners-ref.html @@ -7,7 +7,6 @@ #container { width: 300px; height: 300px; - border: 5px solid black; border-radius: 50%; overflow: hidden; } diff --git a/Tests/LibWeb/Ref/input/scrolled-text-with-clipped-corners.html b/Tests/LibWeb/Ref/input/scrolled-text-with-clipped-corners.html index 4c1749cab97..c50b1550823 100644 --- a/Tests/LibWeb/Ref/input/scrolled-text-with-clipped-corners.html +++ b/Tests/LibWeb/Ref/input/scrolled-text-with-clipped-corners.html @@ -5,15 +5,27 @@ scrollbar-width: none; } + #outer { + /* + This needs to be here so that the text is double-clipped. + This happens in the reference and causes a slight difference + in aliasing around the edges. + */ + width: 300px; + height: 300px; + border-radius: 50%; + overflow: hidden; + } + #container { width: 300px; height: 300px; - border: 5px solid black; border-radius: 50%; overflow: scroll; font-size: 40px; } +
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut ultrices neque eu nisi facilisis viverra. Integer lacinia, lacus vel condimentum suscipit, lacus felis porta nulla, eget lacinia @@ -23,6 +35,7 @@ non elit in vehicula. Etiam malesuada neque eu porta rhoncus. Curabitur vel nunc finibus ligula posuere venenatis.
+