From 9e2c4f84fd03452a6a936cd2d27ea625038a662f Mon Sep 17 00:00:00 2001 From: MacDue Date: Sun, 26 May 2024 00:28:48 +0100 Subject: [PATCH] LibWeb: Paint/apply `basic-shape` clip paths to PaintableBoxes Currently, these only work when there are no CSS transforms (as the stacking context painting is not set up to handle that case yet). This is still enough to get most chat/comment markers working on GitHub though :^) --- .../LibWeb/Painting/PaintableBox.cpp | 37 +++++++++++++++++++ .../Libraries/LibWeb/Painting/PaintableBox.h | 6 +-- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp index b7053d48bfa..fc6a9109343 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -869,4 +869,41 @@ void PaintableBox::set_needs_display() const navigable->set_needs_display(absolute_rect()); } +Optional PaintableBox::get_masking_area() const +{ + // FIXME: Support clip-paths with transforms. + if (!combined_css_transform().is_identity_or_translation()) + return {}; + auto clip_path = computed_values().clip_path(); + // FIXME: Support other clip sources. + if (!clip_path.has_value() || !clip_path->is_basic_shape()) + return {}; + // FIXME: Support other geometry boxes. See: https://drafts.fxtf.org/css-masking/#typedef-geometry-box + 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::Painter painter(*bitmap); + Gfx::AntiAliasingPainter aa_painter(painter); + aa_painter.fill_path(path, Color::Black); + return bitmap; +} + } diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.h b/Userland/Libraries/LibWeb/Painting/PaintableBox.h index 1c2e5d3ba0d..3c7dc37c1f7 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.h +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.h @@ -29,9 +29,9 @@ public: virtual void paint(PaintContext&, PaintPhase) const override; - virtual Optional get_masking_area() const { return {}; } - virtual Optional get_mask_type() const { return {}; } - virtual RefPtr calculate_mask(PaintContext&, CSSPixelRect const&) const { return {}; } + virtual Optional get_masking_area() const; + virtual Optional get_mask_type() const; + virtual RefPtr calculate_mask(PaintContext&, CSSPixelRect const&) const; Layout::Box& layout_box() { return static_cast(Paintable::layout_node()); } Layout::Box const& layout_box() const { return static_cast(Paintable::layout_node()); }