diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp index 36a0c8f1dc..2c33f7125a 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -246,17 +246,48 @@ void PaintableBox::before_children_paint(PaintContext& context, PaintPhase) cons { // FIXME: Support more overflow variations. auto clip_rect = absolute_padding_box_rect().to_rounded(); - if (computed_values().overflow_x() == CSS::Overflow::Hidden && computed_values().overflow_y() == CSS::Overflow::Hidden) { - context.painter().save(); - context.painter().add_clip_rect(clip_rect); + auto overflow_x = computed_values().overflow_x(); + auto overflow_y = computed_values().overflow_y(); + + auto clip_overflow = [&] { + if (!m_clipping_overflow) { + context.painter().save(); + context.painter().add_clip_rect(clip_rect); + m_clipping_overflow = true; + } + }; + + if (overflow_x == CSS::Overflow::Hidden && overflow_y == CSS::Overflow::Hidden) { + clip_overflow(); + } + if (overflow_y == CSS::Overflow::Hidden || overflow_x == CSS::Overflow::Hidden) { + auto border_radii_data = normalized_border_radii_data(); + auto const& border = box_model().border; + border_radii_data.shrink(border.top, border.right, border.bottom, border.left); + if (border_radii_data.has_any_radius()) { + auto corner_clipper = BorderRadiusCornerClipper::create(clip_rect, border_radii_data, CornerClip::Outside, BorderRadiusCornerClipper::UseCachedBitmap::No); + if (corner_clipper.is_error()) { + dbgln("Failed to create overflow border-radius corner clipper: {}", corner_clipper.error()); + return; + } + clip_overflow(); + m_overflow_corner_radius_clipper = corner_clipper.release_value(); + m_overflow_corner_radius_clipper->sample_under_corners(context.painter()); + } } } void PaintableBox::after_children_paint(PaintContext& context, PaintPhase) const { // FIXME: Support more overflow variations. - if (computed_values().overflow_x() == CSS::Overflow::Hidden && computed_values().overflow_y() == CSS::Overflow::Hidden) + if (m_clipping_overflow) { context.painter().restore(); + m_clipping_overflow = false; + } + if (m_overflow_corner_radius_clipper.has_value()) { + m_overflow_corner_radius_clipper->blit_corner_clipping(context.painter()); + m_overflow_corner_radius_clipper = {}; + } } static void paint_cursor_if_needed(PaintContext& context, Layout::TextNode const& text_node, Layout::LineBoxFragment const& fragment) @@ -416,13 +447,24 @@ void PaintableWithLines::paint(PaintContext& context, PaintPhase phase) const return; bool should_clip_overflow = computed_values().overflow_x() != CSS::Overflow::Visible && computed_values().overflow_y() != CSS::Overflow::Visible; + Optional corner_clipper; if (should_clip_overflow) { context.painter().save(); // FIXME: Handle overflow-x and overflow-y being different values. - context.painter().add_clip_rect(enclosing_int_rect(absolute_padding_box_rect())); + auto clip_box = absolute_padding_box_rect().to_rounded(); + context.painter().add_clip_rect(clip_box); auto scroll_offset = static_cast(layout_box()).scroll_offset(); context.painter().translate(-scroll_offset.to_type()); + + auto border_radii = normalized_border_radii_data(); + if (border_radii.has_any_radius()) { + auto clipper = BorderRadiusCornerClipper::create(clip_box, border_radii); + if (!clipper.is_error()) { + corner_clipper = clipper.release_value(); + corner_clipper->sample_under_corners(context.painter()); + } + } } // Text shadows @@ -470,6 +512,8 @@ void PaintableWithLines::paint(PaintContext& context, PaintPhase phase) const if (should_clip_overflow) { context.painter().restore(); + if (corner_clipper.has_value()) + corner_clipper->blit_corner_clipping(context.painter()); } // FIXME: Merge this loop with the above somehow.. diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.h b/Userland/Libraries/LibWeb/Painting/PaintableBox.h index 02a4d319bd..d2c1e2503b 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.h +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include namespace Web::Painting { @@ -135,6 +136,9 @@ private: OwnPtr m_stacking_context; Optional mutable m_absolute_rect; + + mutable bool m_clipping_overflow { false }; + Optional mutable m_overflow_corner_radius_clipper; }; class PaintableWithLines : public PaintableBox {