diff --git a/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp b/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp index ccc1983d83..3c69258a24 100644 --- a/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp +++ b/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp @@ -33,11 +33,7 @@ struct CommandExecutionState { CommandResult FillRectWithRoundedCorners::execute(CommandExecutionState& state) const { - if (state.would_be_fully_clipped_by_painter(rect)) - return CommandResult::Continue; - auto& painter = state.painter(); - Gfx::AntiAliasingPainter aa_painter(painter); if (aa_translation.has_value()) aa_painter.translate(*aa_translation); @@ -75,8 +71,6 @@ CommandResult DrawTextRun::execute(CommandExecutionState& state) const CommandResult FillPathUsingColor::execute(CommandExecutionState& state) const { - if (state.would_be_fully_clipped_by_painter(bounding_rect)) - return CommandResult::Continue; auto& painter = state.painter(); Gfx::AntiAliasingPainter aa_painter(painter); if (aa_translation.has_value()) @@ -87,8 +81,6 @@ CommandResult FillPathUsingColor::execute(CommandExecutionState& state) const CommandResult FillPathUsingPaintStyle::execute(CommandExecutionState& state) const { - if (state.would_be_fully_clipped_by_painter(bounding_rect)) - return CommandResult::Continue; auto& painter = state.painter(); Gfx::AntiAliasingPainter aa_painter(painter); if (aa_translation.has_value()) @@ -99,8 +91,6 @@ CommandResult FillPathUsingPaintStyle::execute(CommandExecutionState& state) con CommandResult StrokePathUsingColor::execute(CommandExecutionState& state) const { - if (state.would_be_fully_clipped_by_painter(bounding_rect)) - return CommandResult::Continue; auto& painter = state.painter(); Gfx::AntiAliasingPainter aa_painter(painter); if (aa_translation.has_value()) @@ -111,8 +101,6 @@ CommandResult StrokePathUsingColor::execute(CommandExecutionState& state) const CommandResult StrokePathUsingPaintStyle::execute(CommandExecutionState& state) const { - if (state.would_be_fully_clipped_by_painter(bounding_rect)) - return CommandResult::Continue; auto& painter = state.painter(); Gfx::AntiAliasingPainter aa_painter(painter); if (aa_translation.has_value()) @@ -123,8 +111,6 @@ CommandResult StrokePathUsingPaintStyle::execute(CommandExecutionState& state) c CommandResult FillRect::execute(CommandExecutionState& state) const { - if (state.would_be_fully_clipped_by_painter(rect)) - return CommandResult::Continue; auto& painter = state.painter(); painter.fill_rect(rect, color); return CommandResult::Continue; @@ -132,8 +118,6 @@ CommandResult FillRect::execute(CommandExecutionState& state) const CommandResult DrawScaledBitmap::execute(CommandExecutionState& state) const { - if (state.would_be_fully_clipped_by_painter(dst_rect)) - return CommandResult::Continue; auto& painter = state.painter(); painter.draw_scaled_bitmap(dst_rect, bitmap, src_rect, opacity, scaling_mode); return CommandResult::Continue; @@ -290,8 +274,6 @@ CommandResult PopStackingContextWithMask::execute(CommandExecutionState& state) CommandResult PaintLinearGradient::execute(CommandExecutionState& state) const { - if (state.would_be_fully_clipped_by_painter(gradient_rect)) - return CommandResult::Continue; auto const& data = linear_gradient_data; state.painter().fill_rect_with_linear_gradient( gradient_rect, data.color_stops.list, @@ -301,8 +283,6 @@ CommandResult PaintLinearGradient::execute(CommandExecutionState& state) const CommandResult PaintRadialGradient::execute(CommandExecutionState& state) const { - if (state.would_be_fully_clipped_by_painter(rect)) - return CommandResult::Continue; auto& painter = state.painter(); painter.fill_rect_with_radial_gradient(rect, radial_gradient_data.color_stops.list, center, size, radial_gradient_data.color_stops.repeat_length); return CommandResult::Continue; @@ -310,18 +290,18 @@ CommandResult PaintRadialGradient::execute(CommandExecutionState& state) const CommandResult PaintConicGradient::execute(CommandExecutionState& state) const { - if (state.would_be_fully_clipped_by_painter(rect)) - return CommandResult::Continue; auto& painter = state.painter(); painter.fill_rect_with_conic_gradient(rect, conic_gradient_data.color_stops.list, position, conic_gradient_data.start_angle, conic_gradient_data.color_stops.repeat_length); return CommandResult::Continue; } +Gfx::IntRect PaintOuterBoxShadow::bounding_rect() const +{ + return get_outer_box_shadow_bounding_rect(outer_box_shadow_params); +} + CommandResult PaintOuterBoxShadow::execute(CommandExecutionState& state) const { - auto bounding_rect = get_outer_box_shadow_bounding_rect(outer_box_shadow_params); - if (state.would_be_fully_clipped_by_painter(bounding_rect)) - return CommandResult::Continue; auto& painter = state.painter(); paint_outer_box_shadow(painter, outer_box_shadow_params); return CommandResult::Continue; @@ -340,9 +320,9 @@ CommandResult PaintTextShadow::execute(CommandExecutionState& state) const return CommandResult::Continue; // FIXME: Figure out the maximum bitmap size for all shadows and then allocate it once and reuse it? - auto maybe_shadow_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, bounding_rect.size()); + auto maybe_shadow_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, shadow_bounding_rect.size()); if (maybe_shadow_bitmap.is_error()) { - dbgln("Unable to allocate temporary bitmap {} for text-shadow rendering: {}", bounding_rect.size(), maybe_shadow_bitmap.error()); + dbgln("Unable to allocate temporary bitmap {} for text-shadow rendering: {}", shadow_bounding_rect.size(), maybe_shadow_bitmap.error()); return CommandResult::Continue; } auto shadow_bitmap = maybe_shadow_bitmap.release_value(); @@ -357,14 +337,12 @@ CommandResult PaintTextShadow::execute(CommandExecutionState& state) const filter.process_rgba(blur_radius, color); auto& painter = state.painter(); - painter.blit(draw_location, *shadow_bitmap, bounding_rect); + painter.blit(draw_location, *shadow_bitmap, shadow_bounding_rect); return CommandResult::Continue; } CommandResult DrawEllipse::execute(CommandExecutionState& state) const { - if (state.would_be_fully_clipped_by_painter(rect)) - return CommandResult::Continue; auto& painter = state.painter(); Gfx::AntiAliasingPainter aa_painter(painter); aa_painter.draw_ellipse(rect, color, thickness); @@ -373,8 +351,6 @@ CommandResult DrawEllipse::execute(CommandExecutionState& state) const CommandResult FillElipse::execute(CommandExecutionState& state) const { - if (state.would_be_fully_clipped_by_painter(rect)) - return CommandResult::Continue; auto& painter = state.painter(); Gfx::AntiAliasingPainter aa_painter(painter); aa_painter.fill_ellipse(rect, color, blend_mode); @@ -394,8 +370,6 @@ CommandResult DrawLine::execute(CommandExecutionState& state) const CommandResult DrawSignedDistanceField::execute(CommandExecutionState& state) const { - if (state.would_be_fully_clipped_by_painter(rect)) - return CommandResult::Continue; auto& painter = state.painter(); painter.draw_signed_distance_field(rect, color, sdf, smoothing); return CommandResult::Continue; @@ -455,8 +429,6 @@ CommandResult ApplyBackdropFilter::execute(CommandExecutionState& state) const CommandResult DrawRect::execute(CommandExecutionState& state) const { - if (state.would_be_fully_clipped_by_painter(rect)) - return CommandResult::Continue; auto& painter = state.painter(); painter.draw_rect(rect, color, rough); return CommandResult::Continue; @@ -469,19 +441,25 @@ CommandResult DrawTriangleWave::execute(CommandExecutionState& state) const return CommandResult::Continue; } +Gfx::IntRect SampleUnderCorners::bounding_rect() const +{ + return corner_clipper->border_rect().to_type(); +} + CommandResult SampleUnderCorners::execute(CommandExecutionState& state) const { - if (state.would_be_fully_clipped_by_painter(corner_clipper->border_rect().to_type())) - return CommandResult::Continue; auto& painter = state.painter(); corner_clipper->sample_under_corners(painter); return CommandResult::Continue; } +Gfx::IntRect BlitCornerClipping::bounding_rect() const +{ + return corner_clipper->border_rect().to_type(); +} + CommandResult BlitCornerClipping::execute(CommandExecutionState& state) const { - if (state.would_be_fully_clipped_by_painter(corner_clipper->border_rect().to_type())) - return CommandResult::Continue; auto& painter = state.painter(); corner_clipper->blit_corner_clipping(painter); return CommandResult::Continue; @@ -507,9 +485,9 @@ void RecordingPainter::fill_rect(Gfx::IntRect const& rect, Color color) void RecordingPainter::fill_path(FillPathUsingColorParams params) { - auto bounding_rect = params.path.bounding_box().translated(params.translation.value_or({})).to_type(); + auto path_bounding_rect = params.path.bounding_box().translated(params.translation.value_or({})).to_type(); push_command(FillPathUsingColor { - .bounding_rect = bounding_rect, + .path_bounding_rect = path_bounding_rect, .path = params.path, .color = params.color, .winding_rule = params.winding_rule, @@ -519,9 +497,9 @@ void RecordingPainter::fill_path(FillPathUsingColorParams params) void RecordingPainter::fill_path(FillPathUsingPaintStyleParams params) { - auto bounding_rect = params.path.bounding_box().translated(params.translation.value_or({})).to_type(); + auto path_bounding_rect = params.path.bounding_box().translated(params.translation.value_or({})).to_type(); push_command(FillPathUsingPaintStyle { - .bounding_rect = bounding_rect, + .path_bounding_rect = path_bounding_rect, .path = params.path, .paint_style = params.paint_style, .winding_rule = params.winding_rule, @@ -532,9 +510,9 @@ void RecordingPainter::fill_path(FillPathUsingPaintStyleParams params) void RecordingPainter::stroke_path(StrokePathUsingColorParams params) { - auto bounding_rect = params.path.bounding_box().translated(params.translation.value_or({})).to_type(); + auto path_bounding_rect = params.path.bounding_box().translated(params.translation.value_or({})).to_type(); push_command(StrokePathUsingColor { - .bounding_rect = bounding_rect, + .path_bounding_rect = path_bounding_rect, .path = params.path, .color = params.color, .thickness = params.thickness, @@ -544,9 +522,9 @@ void RecordingPainter::stroke_path(StrokePathUsingColorParams params) void RecordingPainter::stroke_path(StrokePathUsingPaintStyleParams params) { - auto bounding_rect = params.path.bounding_box().translated(params.translation.value_or({})).to_type(); + auto path_bounding_rect = params.path.bounding_box().translated(params.translation.value_or({})).to_type(); push_command(StrokePathUsingPaintStyle { - .bounding_rect = bounding_rect, + .path_bounding_rect = path_bounding_rect, .path = params.path, .paint_style = params.paint_style, .thickness = params.thickness, @@ -780,7 +758,7 @@ void RecordingPainter::paint_text_shadow(int blur_radius, Gfx::IntRect bounding_ { push_command(PaintTextShadow { .blur_radius = blur_radius, - .bounding_rect = bounding_rect, + .shadow_bounding_rect = bounding_rect, .text_rect = text_rect, .text = String::from_utf8(text.as_string()).release_value_but_fixme_should_propagate_errors(), .font = font, @@ -839,6 +817,17 @@ void RecordingPainter::draw_triangle_wave(Gfx::IntPoint a_p1, Gfx::IntPoint a_p2 .thickness = thickness }); } +static Optional command_bounding_rectangle(PaintingCommand const& command) +{ + return command.visit( + [&](auto const& command) -> Optional { + if constexpr (requires { command.bounding_rect(); }) + return command.bounding_rect(); + else + return {}; + }); +} + void RecordingPainter::execute(Gfx::Bitmap& bitmap) { CommandExecutionState state; @@ -851,8 +840,10 @@ void RecordingPainter::execute(Gfx::Bitmap& bitmap) size_t next_command_index = 0; while (next_command_index < m_painting_commands.size()) { auto& command = m_painting_commands[next_command_index++]; + auto bounding_rect = command_bounding_rectangle(command); + if (bounding_rect.has_value() && state.would_be_fully_clipped_by_painter(*bounding_rect)) + continue; auto result = command.visit([&](auto const& command) { return command.execute(state); }); - if (result == CommandResult::SkipStackingContext) { auto stacking_context_nesting_level = 1; while (next_command_index < m_painting_commands.size()) { diff --git a/Userland/Libraries/LibWeb/Painting/RecordingPainter.h b/Userland/Libraries/LibWeb/Painting/RecordingPainter.h index 0d204e6c80..b0fd6f6233 100644 --- a/Userland/Libraries/LibWeb/Painting/RecordingPainter.h +++ b/Userland/Libraries/LibWeb/Painting/RecordingPainter.h @@ -47,6 +47,7 @@ struct DrawTextRun { NonnullRefPtr font; Gfx::IntRect rect; + [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; } [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; @@ -59,6 +60,7 @@ struct DrawText { Gfx::TextWrapping wrapping; Optional> font {}; + [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; } [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; @@ -66,6 +68,7 @@ struct FillRect { Gfx::IntRect rect; Color color; + [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; } [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; @@ -76,6 +79,7 @@ struct DrawScaledBitmap { float opacity; Gfx::Painter::ScalingMode scaling_mode; + [[nodiscard]] Gfx::IntRect bounding_rect() const { return dst_rect; } [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; @@ -146,12 +150,14 @@ struct PaintLinearGradient { Gfx::IntRect gradient_rect; LinearGradientData linear_gradient_data; + [[nodiscard]] Gfx::IntRect bounding_rect() const { return gradient_rect; } [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; struct PaintOuterBoxShadow { PaintOuterBoxShadowParams outer_box_shadow_params; + [[nodiscard]] Gfx::IntRect bounding_rect() const; [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; @@ -163,7 +169,7 @@ struct PaintInnerBoxShadow { struct PaintTextShadow { int blur_radius; - Gfx::IntRect bounding_rect; + Gfx::IntRect shadow_bounding_rect; Gfx::IntRect text_rect; String text; NonnullRefPtr font; @@ -171,6 +177,7 @@ struct PaintTextShadow { int fragment_baseline; Gfx::IntPoint draw_location; + [[nodiscard]] Gfx::IntRect bounding_rect() const { return shadow_bounding_rect; } [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; @@ -183,48 +190,53 @@ struct FillRectWithRoundedCorners { Gfx::AntiAliasingPainter::CornerRadius bottom_right_radius; Optional aa_translation {}; + [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; } [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; struct FillPathUsingColor { - Gfx::IntRect bounding_rect; + Gfx::IntRect path_bounding_rect; Gfx::Path path; Color color; Gfx::Painter::WindingRule winding_rule; Optional aa_translation {}; + [[nodiscard]] Gfx::IntRect bounding_rect() const { return path_bounding_rect; } [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; struct FillPathUsingPaintStyle { - Gfx::IntRect bounding_rect; + Gfx::IntRect path_bounding_rect; Gfx::Path path; NonnullRefPtr paint_style; Gfx::Painter::WindingRule winding_rule; float opacity; Optional aa_translation {}; + [[nodiscard]] Gfx::IntRect bounding_rect() const { return path_bounding_rect; } [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; struct StrokePathUsingColor { - Gfx::IntRect bounding_rect; + Gfx::IntRect path_bounding_rect; Gfx::Path path; Color color; float thickness; Optional aa_translation {}; + [[nodiscard]] Gfx::IntRect bounding_rect() const { return path_bounding_rect; } [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; struct StrokePathUsingPaintStyle { - Gfx::IntRect bounding_rect; + Gfx::IntRect path_bounding_rect; Gfx::Path path; NonnullRefPtr paint_style; float thickness; float opacity = 1.0f; Optional aa_translation {}; + [[nodiscard]] Gfx::IntRect bounding_rect() const { return path_bounding_rect; } [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; @@ -233,6 +245,7 @@ struct DrawEllipse { Color color; int thickness; + [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; } [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; @@ -241,6 +254,7 @@ struct FillElipse { Color color; Gfx::AntiAliasingPainter::BlendMode blend_mode; + [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; } [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; @@ -261,6 +275,7 @@ struct DrawSignedDistanceField { Gfx::GrayscaleBitmap sdf; float smoothing; + [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; } [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; @@ -273,6 +288,7 @@ struct PaintProgressbar { int value; StringView text; + [[nodiscard]] Gfx::IntRect bounding_rect() const { return frame_rect; } [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; @@ -281,6 +297,7 @@ struct PaintFrame { Palette palette; Gfx::FrameStyle style; + [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; } [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; @@ -289,6 +306,7 @@ struct ApplyBackdropFilter { BorderRadiiData border_radii_data; CSS::ResolvedBackdropFilter backdrop_filter; + [[nodiscard]] Gfx::IntRect bounding_rect() const { return backdrop_region; } [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; @@ -297,6 +315,7 @@ struct DrawRect { Color color; bool rough; + [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; } [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; @@ -306,6 +325,7 @@ struct PaintRadialGradient { Gfx::IntPoint center; Gfx::IntSize size; + [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; } [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; @@ -314,6 +334,7 @@ struct PaintConicGradient { ConicGradientData conic_gradient_data; Gfx::IntPoint position; + [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; } [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; @@ -330,12 +351,14 @@ struct DrawTriangleWave { struct SampleUnderCorners { NonnullRefPtr corner_clipper; + [[nodiscard]] Gfx::IntRect bounding_rect() const; [[nodiscard]] CommandResult execute(CommandExecutionState&) const; }; struct BlitCornerClipping { NonnullRefPtr corner_clipper; + [[nodiscard]] Gfx::IntRect bounding_rect() const; [[nodiscard]] CommandResult execute(CommandExecutionState&) const; };