diff --git a/Userland/Libraries/LibWeb/Painting/BorderRadiiData.h b/Userland/Libraries/LibWeb/Painting/BorderRadiiData.h index 5aa7a3e020..21a4c93b00 100644 --- a/Userland/Libraries/LibWeb/Painting/BorderRadiiData.h +++ b/Userland/Libraries/LibWeb/Painting/BorderRadiiData.h @@ -40,6 +40,11 @@ struct CornerRadii { CornerRadius top_right; CornerRadius bottom_right; CornerRadius bottom_left; + + inline bool has_any_radius() const + { + return top_left || top_right || bottom_right || bottom_left; + } }; struct BorderRadiiData { diff --git a/Userland/Libraries/LibWeb/Painting/BorderRadiusCornerClipper.cpp b/Userland/Libraries/LibWeb/Painting/BorderRadiusCornerClipper.cpp index 96228ed41d..975cbc5ac6 100644 --- a/Userland/Libraries/LibWeb/Painting/BorderRadiusCornerClipper.cpp +++ b/Userland/Libraries/LibWeb/Painting/BorderRadiusCornerClipper.cpp @@ -11,9 +11,9 @@ namespace Web::Painting { -ErrorOr> BorderRadiusCornerClipper::create(CornerRadii const& corner_radii, DevicePixelRect const& border_rect, BorderRadiiData const& border_radii, CornerClip corner_clip) +ErrorOr> BorderRadiusCornerClipper::create(CornerRadii const& corner_radii, DevicePixelRect const& border_rect, CornerClip corner_clip) { - VERIFY(border_radii.has_any_radius()); + VERIFY(corner_radii.has_any_radius()); auto top_left = corner_radii.top_left; auto top_right = corner_radii.top_right; @@ -105,27 +105,26 @@ void BorderRadiusCornerClipper::blit_corner_clipping(Gfx::Painter& painter) ScopedCornerRadiusClip::ScopedCornerRadiusClip(PaintContext& context, DevicePixelRect const& border_rect, BorderRadiiData const& border_radii, CornerClip corner_clip) : m_context(context) + , m_id(context.allocate_corner_clipper_id()) + , m_has_radius(border_radii.has_any_radius()) + , m_border_rect(border_rect) { - if (border_radii.has_any_radius()) { - 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) - }; - auto clipper = BorderRadiusCornerClipper::create(corner_radii, context.recording_painter().state().translation.map(border_rect.to_type()).to_type(), border_radii, corner_clip); - if (!clipper.is_error()) { - m_corner_clipper = clipper.release_value(); - m_context.recording_painter().sample_under_corners(*m_corner_clipper); - } - } + if (!m_has_radius) + return; + CornerRadii const 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) + }; + m_context.recording_painter().sample_under_corners(m_id, corner_radii, context.recording_painter().state().translation.map(border_rect.to_type()), corner_clip); } ScopedCornerRadiusClip::~ScopedCornerRadiusClip() { - if (m_corner_clipper) { - m_context.recording_painter().blit_corner_clipping(*m_corner_clipper); - } + if (!m_has_radius) + return; + m_context.recording_painter().blit_corner_clipping(m_id, m_border_rect); } } diff --git a/Userland/Libraries/LibWeb/Painting/BorderRadiusCornerClipper.h b/Userland/Libraries/LibWeb/Painting/BorderRadiusCornerClipper.h index 01233bbde7..f51c44e1de 100644 --- a/Userland/Libraries/LibWeb/Painting/BorderRadiusCornerClipper.h +++ b/Userland/Libraries/LibWeb/Painting/BorderRadiusCornerClipper.h @@ -18,7 +18,7 @@ enum class CornerClip { class BorderRadiusCornerClipper : public RefCounted { public: - static ErrorOr> create(CornerRadii const&, DevicePixelRect const& border_rect, BorderRadiiData const& border_radii, CornerClip corner_clip = CornerClip::Outside); + static ErrorOr> create(CornerRadii const&, DevicePixelRect const& border_rect, CornerClip corner_clip = CornerClip::Outside); void sample_under_corners(Gfx::Painter& page_painter); void blit_corner_clipping(Gfx::Painter& page_painter); @@ -63,6 +63,9 @@ struct ScopedCornerRadiusClip { private: PaintContext& m_context; RefPtr m_corner_clipper; + u32 m_id; + bool m_has_radius { false }; + Gfx::IntRect m_border_rect; }; } diff --git a/Userland/Libraries/LibWeb/Painting/PaintContext.h b/Userland/Libraries/LibWeb/Painting/PaintContext.h index f8b0d8f762..6303058c23 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintContext.h +++ b/Userland/Libraries/LibWeb/Painting/PaintContext.h @@ -71,6 +71,8 @@ public: CSSPixelPoint scroll_offset() const { return m_scroll_offset; } void translate_scroll_offset_by(CSSPixelPoint offset) { m_scroll_offset.translate_by(offset); } + u32 allocate_corner_clipper_id() { return m_next_corner_clipper_id++; } + private: Painting::RecordingPainter& m_recording_painter; Palette m_palette; @@ -80,6 +82,7 @@ private: bool m_focus { false }; CSSPixelPoint m_scroll_offset; Gfx::AffineTransform m_svg_transform; + u32 m_next_corner_clipper_id { 0 }; }; } diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp index 9fcd8477b8..e4ea3a9bee 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -488,13 +488,9 @@ void PaintableBox::apply_clip_overflow_rect(PaintContext& context, PaintPhase ph .bottom_left = border_radii_data.bottom_left.as_corner(context) }; if (border_radii_data.has_any_radius()) { - auto corner_clipper = BorderRadiusCornerClipper::create(corner_radii, context.recording_painter().state().translation.map(context.rounded_device_rect(*clip_rect).to_type()).to_type(), border_radii_data, CornerClip::Outside); - if (corner_clipper.is_error()) { - dbgln("Failed to create overflow border-radius corner clipper: {}", corner_clipper.error()); - return; - } - m_overflow_corner_radius_clipper = corner_clipper.release_value(); - context.recording_painter().sample_under_corners(*m_overflow_corner_radius_clipper); + VERIFY(!m_corner_clipper_id.has_value()); + m_corner_clipper_id = context.allocate_corner_clipper_id(); + context.recording_painter().sample_under_corners(*m_corner_clipper_id, corner_radii, context.recording_painter().state().translation.map(context.rounded_device_rect(*clip_rect).to_type()), CornerClip::Outside); } } } @@ -509,9 +505,11 @@ void PaintableBox::clear_clip_overflow_rect(PaintContext& context, PaintPhase ph context.recording_painter().restore(); m_clipping_overflow = false; } - if (m_overflow_corner_radius_clipper) { - context.recording_painter().blit_corner_clipping(*m_overflow_corner_radius_clipper); - m_overflow_corner_radius_clipper = nullptr; + if (m_corner_clipper_id.has_value()) { + VERIFY(m_corner_clipper_id.has_value()); + auto clip_rect = this->calculate_overflow_clipped_rect(); + context.recording_painter().blit_corner_clipping(*m_corner_clipper_id, context.recording_painter().state().translation.map(context.rounded_device_rect(*clip_rect).to_type())); + m_corner_clipper_id = {}; } } @@ -681,12 +679,14 @@ 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; - RefPtr corner_clipper; + Optional corner_clip_id; + + auto clip_box = context.rounded_device_rect(absolute_padding_box_rect()); + auto border_radius_clip_rect = context.recording_painter().state().translation.map(clip_box.to_type()); if (should_clip_overflow) { context.recording_painter().save(); // FIXME: Handle overflow-x and overflow-y being different values. - auto clip_box = context.rounded_device_rect(absolute_padding_box_rect()); context.recording_painter().add_clip_rect(clip_box.to_type()); auto scroll_offset = context.rounded_device_point(this->scroll_offset()); context.recording_painter().translate(-scroll_offset.to_type()); @@ -699,11 +699,8 @@ void PaintableWithLines::paint(PaintContext& context, PaintPhase phase) const .bottom_left = border_radii.bottom_left.as_corner(context) }; if (border_radii.has_any_radius()) { - auto clipper = BorderRadiusCornerClipper::create(corner_radii, context.recording_painter().state().translation.map(clip_box.to_type()).to_type(), border_radii); - if (!clipper.is_error()) { - corner_clipper = clipper.release_value(); - context.recording_painter().sample_under_corners(*corner_clipper); - } + corner_clip_id = context.allocate_corner_clipper_id(); + context.recording_painter().sample_under_corners(*corner_clip_id, corner_radii, border_radius_clip_rect, CornerClip::Outside); } } @@ -753,8 +750,10 @@ void PaintableWithLines::paint(PaintContext& context, PaintPhase phase) const if (should_clip_overflow) { context.recording_painter().restore(); - if (corner_clipper) - context.recording_painter().blit_corner_clipping(*corner_clipper); + if (corner_clip_id.has_value()) { + context.recording_painter().blit_corner_clipping(*corner_clip_id, border_radius_clip_rect); + corner_clip_id = {}; + } } } diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.h b/Userland/Libraries/LibWeb/Painting/PaintableBox.h index 63ef8195b9..da0d5bf4fd 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.h +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.h @@ -219,7 +219,7 @@ private: Optional mutable m_clip_rect; mutable bool m_clipping_overflow { false }; - RefPtr mutable m_overflow_corner_radius_clipper; + mutable Optional m_corner_clipper_id; Optional m_override_borders_data; Optional m_table_cell_coordinates; diff --git a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.cpp b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.cpp index 5382e7830a..9a9072365d 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.cpp @@ -414,15 +414,19 @@ CommandResult PaintingCommandExecutorCPU::draw_triangle_wave(Gfx::IntPoint const return CommandResult::Continue; } -CommandResult PaintingCommandExecutorCPU::sample_under_corners(BorderRadiusCornerClipper& corner_clipper) +CommandResult PaintingCommandExecutorCPU::sample_under_corners(u32 id, CornerRadii const& corner_radii, Gfx::IntRect const& border_rect, CornerClip corner_clip) { - corner_clipper.sample_under_corners(painter()); + m_corner_clippers.resize(id + 1); + auto clipper = BorderRadiusCornerClipper::create(corner_radii, border_rect.to_type(), corner_clip); + m_corner_clippers[id] = clipper.release_value_but_fixme_should_propagate_errors(); + m_corner_clippers[id]->sample_under_corners(painter()); return CommandResult::Continue; } -CommandResult PaintingCommandExecutorCPU::blit_corner_clipping(BorderRadiusCornerClipper& corner_clipper) +CommandResult PaintingCommandExecutorCPU::blit_corner_clipping(u32 id) { - corner_clipper.blit_corner_clipping(painter()); + m_corner_clippers[id]->blit_corner_clipping(painter()); + m_corner_clippers[id] = nullptr; return CommandResult::Continue; } diff --git a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.h b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.h index 5746600f9e..06fd099b03 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.h +++ b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.h @@ -43,8 +43,8 @@ public: CommandResult paint_radial_gradient(Gfx::IntRect const& rect, Web::Painting::RadialGradientData const& radial_gradient_data, Gfx::IntPoint const& center, Gfx::IntSize const& size) override; CommandResult paint_conic_gradient(Gfx::IntRect const& rect, Web::Painting::ConicGradientData const& conic_gradient_data, Gfx::IntPoint const& position) override; CommandResult draw_triangle_wave(Gfx::IntPoint const& p1, Gfx::IntPoint const& p2, Color const&, int amplitude, int thickness) override; - CommandResult sample_under_corners(BorderRadiusCornerClipper&) override; - CommandResult blit_corner_clipping(BorderRadiusCornerClipper&) override; + CommandResult sample_under_corners(u32 id, CornerRadii const&, Gfx::IntRect const&, CornerClip) override; + CommandResult blit_corner_clipping(u32 id) override; CommandResult paint_borders(DevicePixelRect const& border_rect, CornerRadii const& corner_radii, BordersDataDevicePixels const& borders_data) override; bool would_be_fully_clipped_by_painter(Gfx::IntRect) const override; @@ -59,6 +59,7 @@ public: private: Gfx::Bitmap& m_target_bitmap; + Vector> m_corner_clippers; struct StackingContext { MaybeOwned painter; diff --git a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.cpp b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.cpp index a3540edab0..bf65430d3b 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.cpp @@ -299,13 +299,13 @@ CommandResult PaintingCommandExecutorGPU::draw_triangle_wave(Gfx::IntPoint const return CommandResult::Continue; } -CommandResult PaintingCommandExecutorGPU::sample_under_corners(BorderRadiusCornerClipper&) +CommandResult PaintingCommandExecutorGPU::sample_under_corners(u32, CornerRadii const&, Gfx::IntRect const&, CornerClip) { // FIXME return CommandResult::Continue; } -CommandResult PaintingCommandExecutorGPU::blit_corner_clipping(BorderRadiusCornerClipper&) +CommandResult PaintingCommandExecutorGPU::blit_corner_clipping(u32) { // FIXME return CommandResult::Continue; diff --git a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.h b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.h index fb7d418efe..5da58467ad 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.h +++ b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.h @@ -44,8 +44,8 @@ public: CommandResult paint_radial_gradient(Gfx::IntRect const& rect, Web::Painting::RadialGradientData const& radial_gradient_data, Gfx::IntPoint const& center, Gfx::IntSize const& size) override; CommandResult paint_conic_gradient(Gfx::IntRect const& rect, Web::Painting::ConicGradientData const& conic_gradient_data, Gfx::IntPoint const& position) override; CommandResult draw_triangle_wave(Gfx::IntPoint const& p1, Gfx::IntPoint const& p2, Color const&, int amplitude, int thickness) override; - CommandResult sample_under_corners(BorderRadiusCornerClipper&) override; - CommandResult blit_corner_clipping(BorderRadiusCornerClipper&) override; + CommandResult sample_under_corners(u32 id, CornerRadii const&, Gfx::IntRect const&, CornerClip) override; + CommandResult blit_corner_clipping(u32) override; CommandResult paint_borders(DevicePixelRect const& border_rect, CornerRadii const& corner_radii, BordersDataDevicePixels const& borders_data) override; bool would_be_fully_clipped_by_painter(Gfx::IntRect) const override; diff --git a/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp b/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp index 8a5cf9c7e6..b758b32f19 100644 --- a/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp +++ b/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp @@ -16,22 +16,26 @@ Gfx::IntRect PaintOuterBoxShadow::bounding_rect() const Gfx::IntRect SampleUnderCorners::bounding_rect() const { - return corner_clipper->border_rect().to_type(); + return border_rect; } Gfx::IntRect BlitCornerClipping::bounding_rect() const { - return corner_clipper->border_rect().to_type(); + return border_rect; } -void RecordingPainter::sample_under_corners(NonnullRefPtr corner_clipper) +void RecordingPainter::sample_under_corners(u32 id, CornerRadii corner_radii, Gfx::IntRect border_rect, CornerClip corner_clip) { - push_command(SampleUnderCorners { corner_clipper }); + push_command(SampleUnderCorners { + id, + corner_radii, + border_rect, + corner_clip }); } -void RecordingPainter::blit_corner_clipping(NonnullRefPtr corner_clipper) +void RecordingPainter::blit_corner_clipping(u32 id, Gfx::IntRect border_rect) { - push_command(BlitCornerClipping { corner_clipper }); + push_command(BlitCornerClipping { id, border_rect }); } void RecordingPainter::fill_rect(Gfx::IntRect const& rect, Color color) @@ -541,10 +545,10 @@ void RecordingPainter::execute(PaintingCommandExecutor& executor) return executor.draw_triangle_wave(command.p1, command.p2, command.color, command.amplitude, command.thickness); }, [&](SampleUnderCorners const& command) { - return executor.sample_under_corners(command.corner_clipper); + return executor.sample_under_corners(command.id, command.corner_radii, command.border_rect, command.corner_clip); }, [&](BlitCornerClipping const& command) { - return executor.blit_corner_clipping(command.corner_clipper); + return executor.blit_corner_clipping(command.id); }, [&](PaintBorders const& command) { return executor.paint_borders(command.border_rect, command.corner_radii, command.borders_data); diff --git a/Userland/Libraries/LibWeb/Painting/RecordingPainter.h b/Userland/Libraries/LibWeb/Painting/RecordingPainter.h index def49bd2c3..46cbf10781 100644 --- a/Userland/Libraries/LibWeb/Painting/RecordingPainter.h +++ b/Userland/Libraries/LibWeb/Painting/RecordingPainter.h @@ -299,13 +299,17 @@ struct DrawTriangleWave { }; struct SampleUnderCorners { - NonnullRefPtr corner_clipper; + u32 id; + CornerRadii corner_radii; + Gfx::IntRect border_rect; + CornerClip corner_clip; [[nodiscard]] Gfx::IntRect bounding_rect() const; }; struct BlitCornerClipping { - NonnullRefPtr corner_clipper; + u32 id; + Gfx::IntRect border_rect; [[nodiscard]] Gfx::IntRect bounding_rect() const; }; @@ -387,8 +391,8 @@ public: virtual CommandResult apply_backdrop_filter(Gfx::IntRect const& backdrop_region, Web::CSS::ResolvedBackdropFilter const& backdrop_filter) = 0; virtual CommandResult draw_rect(Gfx::IntRect const& rect, Color const&, bool rough) = 0; virtual CommandResult draw_triangle_wave(Gfx::IntPoint const& p1, Gfx::IntPoint const& p2, Color const& color, int amplitude, int thickness) = 0; - virtual CommandResult sample_under_corners(BorderRadiusCornerClipper&) = 0; - virtual CommandResult blit_corner_clipping(BorderRadiusCornerClipper&) = 0; + virtual CommandResult sample_under_corners(u32 id, CornerRadii const&, Gfx::IntRect const&, CornerClip) = 0; + virtual CommandResult blit_corner_clipping(u32 id) = 0; virtual CommandResult paint_borders(DevicePixelRect const& border_rect, CornerRadii const& corner_radii, BordersDataDevicePixels const& borders_data) = 0; virtual bool would_be_fully_clipped_by_painter(Gfx::IntRect) const = 0; @@ -482,8 +486,8 @@ public: void push_stacking_context(PushStackingContextParams params); void pop_stacking_context(); - void sample_under_corners(NonnullRefPtr corner_clipper); - void blit_corner_clipping(NonnullRefPtr corner_clipper); + void sample_under_corners(u32 id, CornerRadii corner_radii, Gfx::IntRect border_rect, CornerClip corner_clip); + void blit_corner_clipping(u32 id, Gfx::IntRect border_rect); void paint_progressbar(Gfx::IntRect frame_rect, Gfx::IntRect progress_rect, Palette palette, int min, int max, int value, StringView text); void paint_frame(Gfx::IntRect rect, Palette palette, Gfx::FrameStyle style);