From bc20e3ac6c15c159f9901bd3babe3326450c5e3a Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Tue, 20 Aug 2024 17:27:08 +0200 Subject: [PATCH] LibWeb: Do not allocate mask bitmap for CSS "clip-path" property Instead, it could be applied directly as a clip path in Skia painter. As a side bonus, we get rid of some DeprecatedPath and AntiAliasingPainter usage. --- .../images/clip-path-polygon-ref.png | Bin 3350 -> 3353 bytes .../CSS/StyleValues/BasicShapeStyleValue.cpp | 7 ++--- .../CSS/StyleValues/BasicShapeStyleValue.h | 4 +-- Userland/Libraries/LibWeb/Painting/Command.h | 1 + .../LibWeb/Painting/DisplayListPlayerSkia.cpp | 4 +++ .../LibWeb/Painting/DisplayListRecorder.cpp | 3 ++- .../LibWeb/Painting/DisplayListRecorder.h | 1 + .../LibWeb/Painting/PaintableBox.cpp | 24 ------------------ .../Libraries/LibWeb/Painting/PaintableBox.h | 4 +-- .../LibWeb/Painting/StackingContext.cpp | 9 +++++++ 10 files changed, 25 insertions(+), 32 deletions(-) diff --git a/Tests/LibWeb/Screenshot/images/clip-path-polygon-ref.png b/Tests/LibWeb/Screenshot/images/clip-path-polygon-ref.png index 9978121c55f7366e7b23c54539832e262ddf87ac..deb06fc0c1e5969715bf0fc275be05b71e83ae68 100644 GIT binary patch delta 299 zcmbOxHB)MWiunUi7srr_IdAU<<}G#*aBxhUS}i@l<{QUG-{(hPueEaE?v$S=@nY-u zd+ZDh4iC=f$1^Z6eE2Ugc_EWr{mk_*8?)EGoXE4`9V@a^7Z<<0LHg}FudH&1ZXZ~vKM!oa}5;OXk;vd$@?2>|5Bc8dT2 literal 3350 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>iV_;yIRn}C%z`%3Y)5S5QV$R#Ufq91v z7+4SPcyw>Vo|O?y)V~)e3c~w!vkhrPJxe%3=B4piyAuk85kZ!PG@qdVPIfzpTh^1kSW!2 zIKs}rP|!B}0wY7inUxGX@4uhdz`(%JKDUlZ$%%oXVX>aS*^~<(7^wYLyUo8f}jEegM%9=U?drt7#LDmI7S6W1B78TF^pz}(UO6I tVKgI*)(E3jTJPmMfq{X6!PC{xWt~$(69As-#6|!B diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/BasicShapeStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/BasicShapeStyleValue.cpp index de5084a9aa2..e26a2ddb48f 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/BasicShapeStyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/BasicShapeStyleValue.cpp @@ -5,12 +5,13 @@ */ #include "BasicShapeStyleValue.h" +#include namespace Web::CSS { -Gfx::DeprecatedPath Polygon::to_path(CSSPixelRect reference_box, Layout::Node const& node) const +Gfx::Path Polygon::to_path(CSSPixelRect reference_box, Layout::Node const& node) const { - Gfx::DeprecatedPath path; + Gfx::Path path; bool first = true; for (auto const& point : points) { Gfx::FloatPoint resolved_point { @@ -44,7 +45,7 @@ String Polygon::to_string() const BasicShapeStyleValue::~BasicShapeStyleValue() = default; -Gfx::DeprecatedPath BasicShapeStyleValue::to_path(CSSPixelRect reference_box, Layout::Node const& node) const +Gfx::Path BasicShapeStyleValue::to_path(CSSPixelRect reference_box, Layout::Node const& node) const { return m_basic_shape.visit([&](auto const& shape) { return shape.to_path(reference_box, node); diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/BasicShapeStyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValues/BasicShapeStyleValue.h index 74180b974e8..02436566be1 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/BasicShapeStyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/BasicShapeStyleValue.h @@ -20,7 +20,7 @@ struct Polygon { LengthPercentage y; }; - Gfx::DeprecatedPath to_path(CSSPixelRect reference_box, Layout::Node const&) const; + Gfx::Path to_path(CSSPixelRect reference_box, Layout::Node const&) const; String to_string() const; bool operator==(Polygon const&) const = default; @@ -46,7 +46,7 @@ public: bool properties_equal(BasicShapeStyleValue const& other) const { return m_basic_shape == other.m_basic_shape; } - Gfx::DeprecatedPath to_path(CSSPixelRect reference_box, Layout::Node const&) const; + Gfx::Path to_path(CSSPixelRect reference_box, Layout::Node const&) const; private: BasicShapeStyleValue(BasicShape basic_shape) diff --git a/Userland/Libraries/LibWeb/Painting/Command.h b/Userland/Libraries/LibWeb/Painting/Command.h index 6d17decbc03..5196e83ce7a 100644 --- a/Userland/Libraries/LibWeb/Painting/Command.h +++ b/Userland/Libraries/LibWeb/Painting/Command.h @@ -119,6 +119,7 @@ struct PushStackingContext { Gfx::IntPoint post_transform_translation; StackingContextTransform transform; Optional mask = {}; + Optional clip_path = {}; void translate_by(Gfx::IntPoint const& offset) { diff --git a/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp b/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp index 0dee35765dc..21fb54a5298 100644 --- a/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp +++ b/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp @@ -475,6 +475,10 @@ void DisplayListPlayerSkia::push_stacking_context(PushStackingContext const& com canvas.save(); } + if (command.clip_path.has_value()) { + canvas.clipPath(to_skia_path(command.clip_path.value()), true); + } + if (command.mask.has_value()) { auto alpha_mask = alpha_mask_from_bitmap(*command.mask.value().mask_bitmap, command.mask.value().mask_kind); SkMatrix mask_matrix; diff --git a/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.cpp b/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.cpp index dfb158e4d21..ced6f483038 100644 --- a/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.cpp +++ b/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.cpp @@ -314,7 +314,8 @@ void DisplayListRecorder::push_stacking_context(PushStackingContextParams params .origin = params.transform.origin, .matrix = params.transform.matrix, }, - .mask = params.mask }); + .mask = params.mask, + .clip_path = params.clip_path }); m_state_stack.append(State()); } diff --git a/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.h b/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.h index 9fd291839f9..e329e57e88a 100644 --- a/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.h +++ b/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.h @@ -123,6 +123,7 @@ public: Gfx::IntRect source_paintable_rect; StackingContextTransform transform; Optional mask = {}; + Optional clip_path = {}; }; void push_stacking_context(PushStackingContextParams params); void pop_stacking_context(); diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp index d091b640c09..dcb6f8854e6 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -925,30 +925,6 @@ Optional PaintableBox::get_masking_area() const return absolute_border_box_rect(); } -Optional PaintableBox::get_mask_type() const -{ - // Always an alpha mask as only basic shapes are supported right now. - return Gfx::Bitmap::MaskKind::Alpha; -} - -RefPtr PaintableBox::calculate_mask(PaintContext& context, CSSPixelRect const& masking_area) const -{ - VERIFY(computed_values().clip_path()->is_basic_shape()); - auto const& basic_shape = computed_values().clip_path()->basic_shape(); - auto path = basic_shape.to_path(masking_area, layout_node()); - auto device_pixel_scale = context.device_pixels_per_css_pixel(); - path = path.copy_transformed(Gfx::AffineTransform {}.set_scale(device_pixel_scale, device_pixel_scale)); - auto mask_rect = context.enclosing_device_rect(masking_area); - auto maybe_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, mask_rect.size().to_type()); - if (maybe_bitmap.is_error()) - return {}; - auto bitmap = maybe_bitmap.release_value(); - Gfx::DeprecatedPainter painter(*bitmap); - Gfx::AntiAliasingPainter aa_painter(painter); - aa_painter.fill_path(path, Color::Black); - return bitmap; -} - void PaintableBox::resolve_paint_properties() { auto const& computed_values = this->computed_values(); diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.h b/Userland/Libraries/LibWeb/Painting/PaintableBox.h index 43d8af93acb..bbcee6a5a6b 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.h +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.h @@ -31,8 +31,8 @@ public: virtual void paint(PaintContext&, PaintPhase) const override; virtual Optional get_masking_area() const; - virtual Optional get_mask_type() const; - virtual RefPtr calculate_mask(PaintContext&, CSSPixelRect const&) const; + virtual Optional get_mask_type() const { return {}; } + virtual RefPtr calculate_mask(PaintContext&, CSSPixelRect const&) const { return {}; } Layout::Box& layout_box() { return static_cast(Paintable::layout_node()); } Layout::Box const& layout_box() const { return static_cast(Paintable::layout_node()); } diff --git a/Userland/Libraries/LibWeb/Painting/StackingContext.cpp b/Userland/Libraries/LibWeb/Painting/StackingContext.cpp index 468dc55070f..794eed3e95e 100644 --- a/Userland/Libraries/LibWeb/Painting/StackingContext.cpp +++ b/Userland/Libraries/LibWeb/Painting/StackingContext.cpp @@ -315,6 +315,15 @@ void StackingContext::paint(PaintContext& context) const } } + auto const& computed_values = paintable().computed_values(); + if (auto clip_path = computed_values.clip_path(); clip_path.has_value() && clip_path->is_basic_shape()) { + auto const& masking_area = paintable_box().get_masking_area(); + auto const& basic_shape = computed_values.clip_path()->basic_shape(); + auto path = basic_shape.to_path(*masking_area, paintable().layout_node()); + auto device_pixel_scale = context.device_pixels_per_css_pixel(); + push_stacking_context_params.clip_path = path.copy_transformed(Gfx::AffineTransform {}.set_scale(device_pixel_scale, device_pixel_scale).set_translation(source_paintable_rect.location().to_type())); + } + auto has_css_transform = paintable().is_paintable_box() && paintable_box().has_css_transform(); context.display_list_recorder().save(); if (has_css_transform) {