diff --git a/Tests/LibWeb/Screenshot/images/css-background-clip-text.png b/Tests/LibWeb/Screenshot/images/css-background-clip-text.png index 69ffed3e36d..a86a410fc0f 100644 Binary files a/Tests/LibWeb/Screenshot/images/css-background-clip-text.png and b/Tests/LibWeb/Screenshot/images/css-background-clip-text.png differ diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/AbstractImageStyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValues/AbstractImageStyleValue.h index 1327198b4cb..eac8e478657 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/AbstractImageStyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/AbstractImageStyleValue.h @@ -36,7 +36,7 @@ public: virtual void resolve_for_size(Layout::NodeWithStyleAndBoxModelMetrics const&, CSSPixelSize) const {}; virtual bool is_paintable() const = 0; - virtual void paint(PaintContext& context, DevicePixelRect const& dest_rect, ImageRendering, Vector const& clip_paths = {}) const = 0; + virtual void paint(PaintContext& context, DevicePixelRect const& dest_rect, ImageRendering, RefPtr text_clip = {}) const = 0; virtual Optional color_if_single_pixel_bitmap() const { return {}; } }; diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/ConicGradientStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/ConicGradientStyleValue.cpp index 53ad12c6d59..669e1c70870 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/ConicGradientStyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/ConicGradientStyleValue.cpp @@ -42,12 +42,12 @@ void ConicGradientStyleValue::resolve_for_size(Layout::NodeWithStyleAndBoxModelM m_resolved->position = m_properties.position->resolved(node, CSSPixelRect { { 0, 0 }, size }); } -void ConicGradientStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering, Vector const& clip_paths) const +void ConicGradientStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering, RefPtr text_clip) const { VERIFY(m_resolved.has_value()); auto destination_rect = dest_rect.to_type(); auto position = context.rounded_device_point(m_resolved->position).to_type(); - context.display_list_recorder().fill_rect_with_conic_gradient(destination_rect, m_resolved->data, position, clip_paths); + context.display_list_recorder().fill_rect_with_conic_gradient(destination_rect, m_resolved->data, position, text_clip); } bool ConicGradientStyleValue::equals(StyleValue const& other) const diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/ConicGradientStyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValues/ConicGradientStyleValue.h index 2a5a73b138a..0327abf6dad 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/ConicGradientStyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/ConicGradientStyleValue.h @@ -25,7 +25,7 @@ public: virtual String to_string() const override; - void paint(PaintContext&, DevicePixelRect const& dest_rect, CSS::ImageRendering, Vector const& clip_paths = {}) const override; + void paint(PaintContext&, DevicePixelRect const& dest_rect, CSS::ImageRendering, RefPtr text_clip = {}) const override; virtual bool equals(StyleValue const& other) const override; diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp index 37e1dfa493e..0e276492df1 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp @@ -133,11 +133,11 @@ Optional ImageStyleValue::natural_aspect_ratio() const return {}; } -void ImageStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering, Vector const& clip_paths) const +void ImageStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering, RefPtr text_clip) const { if (auto const* b = bitmap(m_current_frame_index, dest_rect.size().to_type()); b != nullptr) { auto scaling_mode = to_gfx_scaling_mode(image_rendering, b->rect(), dest_rect.to_type()); - context.display_list_recorder().draw_scaled_immutable_bitmap(dest_rect.to_type(), *b, b->rect(), scaling_mode, clip_paths); + context.display_list_recorder().draw_scaled_immutable_bitmap(dest_rect.to_type(), *b, b->rect(), scaling_mode, text_clip); } } diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.h index d77d8c6ac8a..8074cf768e6 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.h @@ -45,7 +45,7 @@ public: Optional natural_aspect_ratio() const override; virtual bool is_paintable() const override; - void paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering, Vector const& clip_paths = {}) const override; + void paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering, RefPtr clip_paths = {}) const override; virtual Optional color_if_single_pixel_bitmap() const override; Gfx::ImmutableBitmap const* current_frame_bitmap(DevicePixelRect const& dest_rect) const; diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/LinearGradientStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/LinearGradientStyleValue.cpp index 2786b9de32c..37dc9b047e5 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/LinearGradientStyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/LinearGradientStyleValue.cpp @@ -109,10 +109,10 @@ void LinearGradientStyleValue::resolve_for_size(Layout::NodeWithStyleAndBoxModel m_resolved = ResolvedData { Painting::resolve_linear_gradient_data(node, size, *this), size }; } -void LinearGradientStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering, Vector const& clip_paths) const +void LinearGradientStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering, RefPtr text_clip) const { VERIFY(m_resolved.has_value()); - context.display_list_recorder().fill_rect_with_linear_gradient(dest_rect.to_type(), m_resolved->data, clip_paths); + context.display_list_recorder().fill_rect_with_linear_gradient(dest_rect.to_type(), m_resolved->data, text_clip); } } diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/LinearGradientStyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValues/LinearGradientStyleValue.h index 06b46e192f9..53e7581d5a4 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/LinearGradientStyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/LinearGradientStyleValue.h @@ -60,7 +60,7 @@ public: void resolve_for_size(Layout::NodeWithStyleAndBoxModelMetrics const&, CSSPixelSize) const override; bool is_paintable() const override { return true; } - void paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering, Vector const& clip_paths = {}) const override; + void paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering, RefPtr text_clip = {}) const override; private: LinearGradientStyleValue(GradientDirection direction, Vector color_stop_list, GradientType type, GradientRepeating repeating) diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/RadialGradientStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/RadialGradientStyleValue.cpp index 99a7a93ddca..c38324dc8c3 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/RadialGradientStyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/RadialGradientStyleValue.cpp @@ -207,12 +207,12 @@ bool RadialGradientStyleValue::equals(StyleValue const& other) const return m_properties == other_gradient.m_properties; } -void RadialGradientStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering, Vector const& clip_paths) const +void RadialGradientStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering, RefPtr text_clip) const { VERIFY(m_resolved.has_value()); auto center = context.rounded_device_point(m_resolved->center).to_type(); auto size = context.rounded_device_size(m_resolved->gradient_size).to_type(); - context.display_list_recorder().fill_rect_with_radial_gradient(dest_rect.to_type(), m_resolved->data, center, size, clip_paths); + context.display_list_recorder().fill_rect_with_radial_gradient(dest_rect.to_type(), m_resolved->data, center, size, text_clip); } } diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/RadialGradientStyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValues/RadialGradientStyleValue.h index bfe5556de88..bd8f79f66c4 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/RadialGradientStyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/RadialGradientStyleValue.h @@ -51,7 +51,7 @@ public: virtual String to_string() const override; - void paint(PaintContext&, DevicePixelRect const& dest_rect, CSS::ImageRendering, Vector const& clip_paths = {}) const override; + void paint(PaintContext&, DevicePixelRect const& dest_rect, CSS::ImageRendering, RefPtr text_clip = {}) const override; virtual bool equals(StyleValue const& other) const override; diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 5b9368cbab9..a41a5123dbe 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -25,6 +25,7 @@ class XMLDocumentBuilder; namespace Web::Painting { class BackingStore; +class DisplayList; class DisplayListRecorder; class SVGGradientPaintStyle; using PaintStyle = RefPtr; diff --git a/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp b/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp index 664149ac770..2caa8b272b0 100644 --- a/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp +++ b/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp @@ -58,47 +58,21 @@ static CSSPixelSize run_default_sizing_algorithm( return default_size; } -static Vector compute_text_clip_paths(PaintContext& context, Paintable const& paintable) +static RefPtr compute_text_clip_paths(PaintContext& context, Paintable const& paintable) { - Vector text_clip_paths; + auto text_clip_paths = DisplayList::create(); + DisplayListRecorder display_list_recorder(*text_clip_paths); auto add_text_clip_path = [&](PaintableFragment const& fragment) { auto glyph_run = fragment.glyph_run(); if (!glyph_run || glyph_run->glyphs().is_empty()) return; - // Scale to the device pixels. - Gfx::Path glyph_run_path; - auto const& font = fragment.glyph_run()->font(); - auto scaled_font = font.with_size(font.point_size() * static_cast(context.device_pixels_per_css_pixel())); - for (auto glyph : fragment.glyph_run()->glyphs()) { - glyph.visit([&](auto& glyph) { - glyph.position = glyph.position.scaled(context.device_pixels_per_css_pixel()); - }); - if (glyph.has()) { - auto const& draw_glyph = glyph.get(); - - // Get the path for the glyph. - Gfx::Path glyph_path; - auto glyph_id = scaled_font->glyph_id_for_code_point(draw_glyph.code_point); - scaled_font->append_glyph_path_to(glyph_path, glyph_id); - - // Transform the path to the fragment's position. - // FIXME: Record glyphs and use Painter::draw_glyphs() instead to avoid this duplicated code. - auto top_left = draw_glyph.position + Gfx::FloatPoint(scaled_font->glyph_left_bearing(draw_glyph.code_point), 0); - auto glyph_position = Gfx::GlyphRasterPosition::get_nearest_fit_for(top_left); - auto transform = Gfx::AffineTransform {}.translate(glyph_position.blit_position.to_type()); - glyph_run_path.append_path(glyph_path.copy_transformed(transform)); - } - } - - // Calculate the baseline start position. auto fragment_absolute_rect = fragment.absolute_rect(); auto fragment_absolute_device_rect = context.enclosing_device_rect(fragment_absolute_rect); - DevicePixelPoint baseline_start { fragment_absolute_device_rect.x(), fragment_absolute_device_rect.y() + context.rounded_device_pixels(fragment.baseline()) }; - // Add the path to text_clip_paths. - auto transform = Gfx::AffineTransform {}.translate(baseline_start.to_type().to_type()); - text_clip_paths.append(glyph_run_path.copy_transformed(transform)); + DevicePixelPoint baseline_start { fragment_absolute_device_rect.x(), fragment_absolute_device_rect.y() + context.rounded_device_pixels(fragment.baseline()) }; + auto scale = context.device_pixels_per_css_pixel(); + display_list_recorder.draw_text_run(baseline_start.to_type(), *glyph_run, Gfx::Color::Black, fragment_absolute_device_rect.to_type(), scale); }; paintable.for_each_in_inclusive_subtree([&](auto& paintable) { @@ -124,9 +98,9 @@ static Vector compute_text_clip_paths(PaintContext& context, Paintabl // https://www.w3.org/TR/css-backgrounds-3/#backgrounds void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMetrics const& layout_node, CSSPixelRect const& border_rect, Color background_color, CSS::ImageRendering image_rendering, Vector const* background_layers, BorderRadiiData const& border_radii) { - Vector clip_paths {}; + RefPtr text_clip; if (background_layers && !background_layers->is_empty() && background_layers->last().clip == CSS::BackgroundBox::Text) { - clip_paths = compute_text_clip_paths(context, *layout_node.paintable()); + text_clip = compute_text_clip_paths(context, *layout_node.paintable()); } auto& display_list_recorder = context.display_list_recorder(); @@ -191,7 +165,7 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet color_box.radii.top_right.as_corner(context), color_box.radii.bottom_right.as_corner(context), color_box.radii.bottom_left.as_corner(context), - clip_paths); + text_clip); if (!has_paintable_layers) return; @@ -459,17 +433,17 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet fill_rect = fill_rect->united(image_device_rect); } }); - display_list_recorder.fill_rect(fill_rect->to_type(), color.value(), clip_paths); + display_list_recorder.fill_rect(fill_rect->to_type(), color.value(), text_clip); } else if (is(image) && repeat_x && repeat_y && !repeat_x_has_gap && !repeat_y_has_gap) { // Use a dedicated painting command for repeated images instead of recording a separate command for each instance // of a repeated background, so the painter has the opportunity to optimize the painting of repeated images. auto dest_rect = context.rounded_device_rect(image_rect); auto const* bitmap = static_cast(image).current_frame_bitmap(dest_rect); auto scaling_mode = to_gfx_scaling_mode(image_rendering, bitmap->rect(), dest_rect.to_type()); - context.display_list_recorder().draw_repeated_immutable_bitmap(dest_rect.to_type(), *bitmap, scaling_mode, { .x = repeat_x, .y = repeat_y }, clip_paths); + context.display_list_recorder().draw_repeated_immutable_bitmap(dest_rect.to_type(), clip_rect.to_type(), *bitmap, scaling_mode, { .x = repeat_x, .y = repeat_y }, text_clip); } else { for_each_image_device_rect([&](auto const& image_device_rect) { - image.paint(context, image_device_rect, image_rendering, clip_paths); + image.paint(context, image_device_rect, image_rendering, text_clip); }); } } diff --git a/Userland/Libraries/LibWeb/Painting/Command.h b/Userland/Libraries/LibWeb/Painting/Command.h index a453ac608f6..0a6b93cb21b 100644 --- a/Userland/Libraries/LibWeb/Painting/Command.h +++ b/Userland/Libraries/LibWeb/Painting/Command.h @@ -33,6 +33,8 @@ namespace Web::Painting { +class DisplayList; + struct DrawGlyphRun { NonnullRefPtr glyph_run; Color color; @@ -48,7 +50,7 @@ struct DrawGlyphRun { struct FillRect { Gfx::IntRect rect; Color color; - Vector clip_paths; + RefPtr text_clip; [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; } void translate_by(Gfx::IntPoint const& offset) { rect.translate_by(offset); } @@ -69,7 +71,7 @@ struct DrawScaledImmutableBitmap { NonnullRefPtr bitmap; Gfx::IntRect src_rect; Gfx::ScalingMode scaling_mode; - Vector clip_paths; + RefPtr text_clip; [[nodiscard]] Gfx::IntRect bounding_rect() const { return dst_rect; } void translate_by(Gfx::IntPoint const& offset) { dst_rect.translate_by(offset); } @@ -82,10 +84,11 @@ struct DrawRepeatedImmutableBitmap { }; Gfx::IntRect dst_rect; + Gfx::IntRect clip_rect; NonnullRefPtr bitmap; Gfx::ScalingMode scaling_mode; Repeat repeat; - Vector clip_paths; + RefPtr text_clip; void translate_by(Gfx::IntPoint const& offset) { dst_rect.translate_by(offset); } }; @@ -129,7 +132,7 @@ struct PopStackingContext { }; struct PaintLinearGradient { Gfx::IntRect gradient_rect; LinearGradientData linear_gradient_data; - Vector clip_paths; + RefPtr text_clip; [[nodiscard]] Gfx::IntRect bounding_rect() const { return gradient_rect; } @@ -170,7 +173,7 @@ struct FillRectWithRoundedCorners { Gfx::IntRect rect; Color color; CornerRadii corner_radii; - Vector clip_paths; + RefPtr text_clip; [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; } void translate_by(Gfx::IntPoint const& offset) { rect.translate_by(offset); } @@ -310,7 +313,7 @@ struct PaintRadialGradient { RadialGradientData radial_gradient_data; Gfx::IntPoint center; Gfx::IntSize size; - Vector clip_paths; + RefPtr text_clip; [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; } @@ -321,7 +324,7 @@ struct PaintConicGradient { Gfx::IntRect rect; ConicGradientData conic_gradient_data; Gfx::IntPoint position; - Vector clip_paths; + RefPtr text_clip; [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; } diff --git a/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp b/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp index 36fe8571ebd..ac31f5d3c62 100644 --- a/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp +++ b/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp @@ -62,6 +62,11 @@ public: m_surface->readPixels(pixmap, 0, 0); } + sk_sp make_surface(int width, int height) + { + return m_surface->makeSurface(width, height); + } + private: sk_sp m_surface; }; @@ -368,17 +373,13 @@ static SkSamplingOptions to_skia_sampling_options(Gfx::ScalingMode scaling_mode) } } -#define APPLY_PATH_CLIP_IF_NEEDED \ - ScopeGuard restore_path_clip { [&] { \ - if (command.clip_paths.size() > 0) \ - surface().canvas().restore(); \ - } }; \ - if (command.clip_paths.size() > 0) { \ - surface().canvas().save(); \ - SkPath clip_path; \ - for (auto const& path : command.clip_paths) \ - clip_path.addPath(to_skia_path(path)); \ - surface().canvas().clipPath(clip_path, true); \ +#define APPLY_TEXT_CLIP_IF_NEEDED(MASK_RECT) \ + ScopeGuard const restore { [&] { \ + if (command.text_clip) \ + surface().canvas().restore(); \ + } }; \ + if (command.text_clip) { \ + apply_mask_painted_from(*command.text_clip, MASK_RECT); \ } DisplayListPlayerSkia::SkiaSurface& DisplayListPlayerSkia::surface() const @@ -422,7 +423,7 @@ void DisplayListPlayerSkia::draw_glyph_run(DrawGlyphRun const& command) void DisplayListPlayerSkia::fill_rect(FillRect const& command) { - APPLY_PATH_CLIP_IF_NEEDED + APPLY_TEXT_CLIP_IF_NEEDED(command.rect) auto const& rect = command.rect; auto& canvas = surface().canvas(); @@ -444,7 +445,7 @@ void DisplayListPlayerSkia::draw_scaled_bitmap(DrawScaledBitmap const& command) void DisplayListPlayerSkia::draw_scaled_immutable_bitmap(DrawScaledImmutableBitmap const& command) { - APPLY_PATH_CLIP_IF_NEEDED + APPLY_TEXT_CLIP_IF_NEEDED(command.dst_rect) auto src_rect = to_skia_rect(command.src_rect); auto dst_rect = to_skia_rect(command.dst_rect); @@ -457,7 +458,7 @@ void DisplayListPlayerSkia::draw_scaled_immutable_bitmap(DrawScaledImmutableBitm void DisplayListPlayerSkia::draw_repeated_immutable_bitmap(DrawRepeatedImmutableBitmap const& command) { - APPLY_PATH_CLIP_IF_NEEDED + APPLY_TEXT_CLIP_IF_NEEDED(command.clip_rect) auto bitmap = to_skia_bitmap(command.bitmap->bitmap()); auto image = SkImages::RasterFromBitmap(bitmap); @@ -655,7 +656,7 @@ static ColorStopList expand_repeat_length(ColorStopList const& color_stop_list, void DisplayListPlayerSkia::paint_linear_gradient(PaintLinearGradient const& command) { - APPLY_PATH_CLIP_IF_NEEDED + APPLY_TEXT_CLIP_IF_NEEDED(command.gradient_rect) auto const& linear_gradient_data = command.linear_gradient_data; auto color_stop_list = linear_gradient_data.color_stops.list; @@ -833,7 +834,7 @@ void DisplayListPlayerSkia::paint_text_shadow(PaintTextShadow const& command) void DisplayListPlayerSkia::fill_rect_with_rounded_corners(FillRectWithRoundedCorners const& command) { - APPLY_PATH_CLIP_IF_NEEDED + APPLY_TEXT_CLIP_IF_NEEDED(command.rect) auto const& rect = command.rect; @@ -1200,7 +1201,7 @@ void DisplayListPlayerSkia::draw_rect(DrawRect const& command) void DisplayListPlayerSkia::paint_radial_gradient(PaintRadialGradient const& command) { - APPLY_PATH_CLIP_IF_NEEDED + APPLY_TEXT_CLIP_IF_NEEDED(command.rect) auto const& radial_gradient_data = command.radial_gradient_data; @@ -1249,7 +1250,7 @@ void DisplayListPlayerSkia::paint_radial_gradient(PaintRadialGradient const& com void DisplayListPlayerSkia::paint_conic_gradient(PaintConicGradient const& command) { - APPLY_PATH_CLIP_IF_NEEDED + APPLY_TEXT_CLIP_IF_NEEDED(command.rect) auto const& conic_gradient_data = command.conic_gradient_data; @@ -1312,4 +1313,22 @@ bool DisplayListPlayerSkia::would_be_fully_clipped_by_painter(Gfx::IntRect rect) return surface().canvas().quickReject(to_skia_rect(rect)); } +void DisplayListPlayerSkia::apply_mask_painted_from(DisplayList& display_list, Gfx::IntRect rect) +{ + auto mask_surface = m_surface->make_surface(rect.width(), rect.height()); + + auto previous_surface = move(m_surface); + m_surface = make(mask_surface); + surface().canvas().translate(-rect.x(), -rect.y()); + execute(display_list); + m_surface = move(previous_surface); + + SkMatrix mask_matrix; + mask_matrix.setTranslate(rect.x(), rect.y()); + auto image = mask_surface->makeImageSnapshot(); + auto shader = image->makeShader(SkSamplingOptions(), mask_matrix); + surface().canvas().save(); + surface().canvas().clipShader(shader); +} + } diff --git a/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.h b/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.h index 1aab26847da..3a9ccc9bf2f 100644 --- a/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.h +++ b/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.h @@ -80,6 +80,8 @@ private: bool would_be_fully_clipped_by_painter(Gfx::IntRect) const override; + void apply_mask_painted_from(DisplayList&, Gfx::IntRect); + class SkiaSurface; SkiaSurface& surface() const; diff --git a/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.cpp b/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.cpp index 3a9df15e223..4ac9113267a 100644 --- a/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.cpp +++ b/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.cpp @@ -42,14 +42,14 @@ void DisplayListRecorder::blit_corner_clipping(u32 id) append(BlitCornerClipping { id, state().translation.map(clip_state.rect) }); } -void DisplayListRecorder::fill_rect(Gfx::IntRect const& rect, Color color, Vector const& clip_paths) +void DisplayListRecorder::fill_rect(Gfx::IntRect const& rect, Color color, RefPtr text_clip) { if (rect.is_empty()) return; append(FillRect { .rect = state().translation.map(rect), .color = color, - .clip_paths = clip_paths, + .text_clip = move(text_clip), }); } @@ -140,17 +140,17 @@ void DisplayListRecorder::fill_ellipse(Gfx::IntRect const& a_rect, Color color) }); } -void DisplayListRecorder::fill_rect_with_linear_gradient(Gfx::IntRect const& gradient_rect, LinearGradientData const& data, Vector const& clip_paths) +void DisplayListRecorder::fill_rect_with_linear_gradient(Gfx::IntRect const& gradient_rect, LinearGradientData const& data, RefPtr text_clip) { if (gradient_rect.is_empty()) return; append(PaintLinearGradient { .gradient_rect = state().translation.map(gradient_rect), .linear_gradient_data = data, - .clip_paths = clip_paths }); + .text_clip = text_clip }); } -void DisplayListRecorder::fill_rect_with_conic_gradient(Gfx::IntRect const& rect, ConicGradientData const& data, Gfx::IntPoint const& position, Vector const& clip_paths) +void DisplayListRecorder::fill_rect_with_conic_gradient(Gfx::IntRect const& rect, ConicGradientData const& data, Gfx::IntPoint const& position, RefPtr text_clip) { if (rect.is_empty()) return; @@ -158,10 +158,10 @@ void DisplayListRecorder::fill_rect_with_conic_gradient(Gfx::IntRect const& rect .rect = state().translation.map(rect), .conic_gradient_data = data, .position = position, - .clip_paths = clip_paths }); + .text_clip = text_clip }); } -void DisplayListRecorder::fill_rect_with_radial_gradient(Gfx::IntRect const& rect, RadialGradientData const& data, Gfx::IntPoint center, Gfx::IntSize size, Vector const& clip_paths) +void DisplayListRecorder::fill_rect_with_radial_gradient(Gfx::IntRect const& rect, RadialGradientData const& data, Gfx::IntPoint center, Gfx::IntSize size, RefPtr text_clip) { if (rect.is_empty()) return; @@ -170,7 +170,7 @@ void DisplayListRecorder::fill_rect_with_radial_gradient(Gfx::IntRect const& rec .radial_gradient_data = data, .center = center, .size = size, - .clip_paths = clip_paths }); + .text_clip = text_clip }); } void DisplayListRecorder::draw_rect(Gfx::IntRect const& rect, Color color, bool rough) @@ -195,7 +195,7 @@ void DisplayListRecorder::draw_scaled_bitmap(Gfx::IntRect const& dst_rect, Gfx:: }); } -void DisplayListRecorder::draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode, Vector const& clip_paths) +void DisplayListRecorder::draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode, RefPtr text_clip) { if (dst_rect.is_empty()) return; @@ -204,18 +204,19 @@ void DisplayListRecorder::draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_r .bitmap = bitmap, .src_rect = src_rect, .scaling_mode = scaling_mode, - .clip_paths = clip_paths, + .text_clip = move(text_clip), }); } -void DisplayListRecorder::draw_repeated_immutable_bitmap(Gfx::IntRect dst_rect, NonnullRefPtr bitmap, Gfx::ScalingMode scaling_mode, DrawRepeatedImmutableBitmap::Repeat repeat, Vector const& clip_paths) +void DisplayListRecorder::draw_repeated_immutable_bitmap(Gfx::IntRect dst_rect, Gfx::IntRect clip_rect, NonnullRefPtr bitmap, Gfx::ScalingMode scaling_mode, DrawRepeatedImmutableBitmap::Repeat repeat, RefPtr text_clip) { append(DrawRepeatedImmutableBitmap { .dst_rect = dst_rect, + .clip_rect = clip_rect, .bitmap = move(bitmap), .scaling_mode = scaling_mode, .repeat = repeat, - .clip_paths = clip_paths, + .text_clip = move(text_clip), }); } @@ -363,7 +364,7 @@ void DisplayListRecorder::paint_text_shadow(int blur_radius, Gfx::IntRect boundi .draw_location = state().translation.map(draw_location) }); } -void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& rect, Color color, Gfx::AntiAliasingPainter::CornerRadius top_left_radius, Gfx::AntiAliasingPainter::CornerRadius top_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_left_radius, Vector const& clip_paths) +void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& rect, Color color, Gfx::AntiAliasingPainter::CornerRadius top_left_radius, Gfx::AntiAliasingPainter::CornerRadius top_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_left_radius, RefPtr clip_paths) { if (rect.is_empty()) return; @@ -382,18 +383,18 @@ void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& rec .bottom_right = bottom_right_radius, .bottom_left = bottom_left_radius, }, - .clip_paths = clip_paths, + .text_clip = clip_paths, }); } -void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int radius, Vector const& clip_paths) +void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int radius, RefPtr clip_paths) { if (a_rect.is_empty()) return; - fill_rect_with_rounded_corners(a_rect, color, radius, radius, radius, radius, clip_paths); + fill_rect_with_rounded_corners(a_rect, color, radius, radius, radius, radius, move(clip_paths)); } -void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int top_left_radius, int top_right_radius, int bottom_right_radius, int bottom_left_radius, Vector const& clip_paths) +void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int top_left_radius, int top_right_radius, int bottom_right_radius, int bottom_left_radius, RefPtr clip_paths) { if (a_rect.is_empty()) return; diff --git a/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.h b/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.h index 6c52fde069d..cf4fa620e90 100644 --- a/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.h +++ b/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.h @@ -40,7 +40,7 @@ class DisplayListRecorder { AK_MAKE_NONMOVABLE(DisplayListRecorder); public: - void fill_rect(Gfx::IntRect const& rect, Color color, Vector const& clip_paths = {}); + void fill_rect(Gfx::IntRect const& rect, Color color, RefPtr text_clip = {}); struct FillPathUsingColorParams { Gfx::Path path; @@ -80,16 +80,16 @@ public: void fill_ellipse(Gfx::IntRect const& a_rect, Color color); - void fill_rect_with_linear_gradient(Gfx::IntRect const& gradient_rect, LinearGradientData const& data, Vector const& clip_paths = {}); - void fill_rect_with_conic_gradient(Gfx::IntRect const& rect, ConicGradientData const& data, Gfx::IntPoint const& position, Vector const& clip_paths = {}); - void fill_rect_with_radial_gradient(Gfx::IntRect const& rect, RadialGradientData const& data, Gfx::IntPoint center, Gfx::IntSize size, Vector const& clip_paths = {}); + void fill_rect_with_linear_gradient(Gfx::IntRect const& gradient_rect, LinearGradientData const& data, RefPtr text_clip = {}); + void fill_rect_with_conic_gradient(Gfx::IntRect const& rect, ConicGradientData const& data, Gfx::IntPoint const& position, RefPtr text_clip = {}); + void fill_rect_with_radial_gradient(Gfx::IntRect const& rect, RadialGradientData const& data, Gfx::IntPoint center, Gfx::IntSize size, RefPtr text_clip = {}); void draw_rect(Gfx::IntRect const& rect, Color color, bool rough = false); void draw_scaled_bitmap(Gfx::IntRect const& dst_rect, Gfx::Bitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode = Gfx::ScalingMode::NearestNeighbor); - void draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode = Gfx::ScalingMode::NearestNeighbor, Vector const& clip_paths = {}); + void draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode = Gfx::ScalingMode::NearestNeighbor, RefPtr text_clip = {}); - void draw_repeated_immutable_bitmap(Gfx::IntRect dst_rect, NonnullRefPtr bitmap, Gfx::ScalingMode scaling_mode, DrawRepeatedImmutableBitmap::Repeat, Vector const& clip_paths = {}); + void draw_repeated_immutable_bitmap(Gfx::IntRect dst_rect, Gfx::IntRect clip_rect, NonnullRefPtr bitmap, Gfx::ScalingMode scaling_mode, DrawRepeatedImmutableBitmap::Repeat, RefPtr text_clip = {}); void draw_line(Gfx::IntPoint from, Gfx::IntPoint to, Color color, int thickness = 1, Gfx::LineStyle style = Gfx::LineStyle::Solid, Color alternate_color = Color::Transparent); @@ -131,9 +131,9 @@ public: void paint_inner_box_shadow_params(PaintBoxShadowParams params); void paint_text_shadow(int blur_radius, Gfx::IntRect bounding_rect, Gfx::IntRect text_rect, Gfx::GlyphRun const&, double glyph_run_scale, Color color, Gfx::IntPoint draw_location); - void fill_rect_with_rounded_corners(Gfx::IntRect const& rect, Color color, Gfx::AntiAliasingPainter::CornerRadius top_left_radius, Gfx::AntiAliasingPainter::CornerRadius top_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_left_radius, Vector const& clip_paths = {}); - void fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int radius, Vector const& clip_paths = {}); - void fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int top_left_radius, int top_right_radius, int bottom_right_radius, int bottom_left_radius, Vector const& clip_paths = {}); + void fill_rect_with_rounded_corners(Gfx::IntRect const& rect, Color color, Gfx::AntiAliasingPainter::CornerRadius top_left_radius, Gfx::AntiAliasingPainter::CornerRadius top_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_left_radius, RefPtr text_clip = {}); + void fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int radius, RefPtr text_clip = {}); + void fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int top_left_radius, int top_right_radius, int bottom_right_radius, int bottom_left_radius, RefPtr text_clip = {}); void draw_triangle_wave(Gfx::IntPoint a_p1, Gfx::IntPoint a_p2, Color color, int amplitude, int thickness);