Procházet zdrojové kódy

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 :^)
MacDue před 1 rokem
rodič
revize
9e2c4f84fd

+ 37 - 0
Userland/Libraries/LibWeb/Painting/PaintableBox.cpp

@@ -869,4 +869,41 @@ void PaintableBox::set_needs_display() const
         navigable->set_needs_display(absolute_rect());
 }
 
+Optional<CSSPixelRect> 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<Gfx::Bitmap::MaskKind> PaintableBox::get_mask_type() const
+{
+    // Always an alpha mask as only basic shapes are supported right now.
+    return Gfx::Bitmap::MaskKind::Alpha;
+}
+
+RefPtr<Gfx::Bitmap> 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<int>());
+    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;
+}
+
 }

+ 3 - 3
Userland/Libraries/LibWeb/Painting/PaintableBox.h

@@ -29,9 +29,9 @@ public:
 
     virtual void paint(PaintContext&, PaintPhase) const override;
 
-    virtual Optional<CSSPixelRect> get_masking_area() const { return {}; }
-    virtual Optional<Gfx::Bitmap::MaskKind> get_mask_type() const { return {}; }
-    virtual RefPtr<Gfx::Bitmap> calculate_mask(PaintContext&, CSSPixelRect const&) const { return {}; }
+    virtual Optional<CSSPixelRect> get_masking_area() const;
+    virtual Optional<Gfx::Bitmap::MaskKind> get_mask_type() const;
+    virtual RefPtr<Gfx::Bitmap> calculate_mask(PaintContext&, CSSPixelRect const&) const;
 
     Layout::Box& layout_box() { return static_cast<Layout::Box&>(Paintable::layout_node()); }
     Layout::Box const& layout_box() const { return static_cast<Layout::Box const&>(Paintable::layout_node()); }