1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 07:17:35 +00:00

LibWeb: Move BorderRadiusCornerClipper allocation into CPU executor

BorderRadiusCornerClipper usage to clip border radius is specific to
CPU painter so it should not be stored in painting commands.

Also with this change bitmaps for corner sampling are allocated during
painting commands replaying instead of commands recording.
This commit is contained in:
Aliaksandr Kalenik 2023-12-05 22:30:32 +01:00 committed by Andreas Kling
parent 89fd8dfaad
commit e8960cf754
12 changed files with 85 additions and 63 deletions

View file

@ -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 {

View file

@ -11,9 +11,9 @@
namespace Web::Painting {
ErrorOr<NonnullRefPtr<BorderRadiusCornerClipper>> BorderRadiusCornerClipper::create(CornerRadii const& corner_radii, DevicePixelRect const& border_rect, BorderRadiiData const& border_radii, CornerClip corner_clip)
ErrorOr<NonnullRefPtr<BorderRadiusCornerClipper>> 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 {
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)
};
auto clipper = BorderRadiusCornerClipper::create(corner_radii, context.recording_painter().state().translation.map(border_rect.to_type<int>()).to_type<DevicePixels>(), border_radii, corner_clip);
if (!clipper.is_error()) {
m_corner_clipper = clipper.release_value();
m_context.recording_painter().sample_under_corners(*m_corner_clipper);
}
}
m_context.recording_painter().sample_under_corners(m_id, corner_radii, context.recording_painter().state().translation.map(border_rect.to_type<int>()), 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);
}
}

View file

@ -18,7 +18,7 @@ enum class CornerClip {
class BorderRadiusCornerClipper : public RefCounted<BorderRadiusCornerClipper> {
public:
static ErrorOr<NonnullRefPtr<BorderRadiusCornerClipper>> create(CornerRadii const&, DevicePixelRect const& border_rect, BorderRadiiData const& border_radii, CornerClip corner_clip = CornerClip::Outside);
static ErrorOr<NonnullRefPtr<BorderRadiusCornerClipper>> 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<BorderRadiusCornerClipper> m_corner_clipper;
u32 m_id;
bool m_has_radius { false };
Gfx::IntRect m_border_rect;
};
}

View file

@ -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 };
};
}

View file

@ -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<int>()).to_type<DevicePixels>(), 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<int>()), 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<int>()));
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<BorderRadiusCornerClipper> corner_clipper;
Optional<u32> 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<int>());
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<int>());
auto scroll_offset = context.rounded_device_point(this->scroll_offset());
context.recording_painter().translate(-scroll_offset.to_type<int>());
@ -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<int>()).to_type<DevicePixels>(), 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 = {};
}
}
}

View file

@ -219,7 +219,7 @@ private:
Optional<CSSPixelRect> mutable m_clip_rect;
mutable bool m_clipping_overflow { false };
RefPtr<BorderRadiusCornerClipper> mutable m_overflow_corner_radius_clipper;
mutable Optional<u32> m_corner_clipper_id;
Optional<BordersDataWithElementKind> m_override_borders_data;
Optional<TableCellCoordinates> m_table_cell_coordinates;

View file

@ -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<DevicePixels>(), 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;
}

View file

@ -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<RefPtr<BorderRadiusCornerClipper>> m_corner_clippers;
struct StackingContext {
MaybeOwned<Gfx::Painter> painter;

View file

@ -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;

View file

@ -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;

View file

@ -16,22 +16,26 @@ Gfx::IntRect PaintOuterBoxShadow::bounding_rect() const
Gfx::IntRect SampleUnderCorners::bounding_rect() const
{
return corner_clipper->border_rect().to_type<int>();
return border_rect;
}
Gfx::IntRect BlitCornerClipping::bounding_rect() const
{
return corner_clipper->border_rect().to_type<int>();
return border_rect;
}
void RecordingPainter::sample_under_corners(NonnullRefPtr<BorderRadiusCornerClipper> 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<BorderRadiusCornerClipper> 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);

View file

@ -299,13 +299,17 @@ struct DrawTriangleWave {
};
struct SampleUnderCorners {
NonnullRefPtr<BorderRadiusCornerClipper> corner_clipper;
u32 id;
CornerRadii corner_radii;
Gfx::IntRect border_rect;
CornerClip corner_clip;
[[nodiscard]] Gfx::IntRect bounding_rect() const;
};
struct BlitCornerClipping {
NonnullRefPtr<BorderRadiusCornerClipper> 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<BorderRadiusCornerClipper> corner_clipper);
void blit_corner_clipping(NonnullRefPtr<BorderRadiusCornerClipper> 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);