1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 06:47:35 +00:00

LibWeb: Support CSS property background-clip: text

From https://drafts.csswg.org/css-backgrounds-4/#background-clip
"The background is painted within (clipped to) the intersection of the
border box and the geometry of the text in the element and its in-flow
and floated descendants"

This change implements it in the following way:
1. Traverse the descendants of the element, collecting the Gfx::Path of
   glyphs into a vector.
2. The vector of collected paths is saved in the background painting
   command.
3. The painting commands executor uses the list of glyphs to paint a
   mask for background clipping.

Co-authored-by: Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
This commit is contained in:
Zac Brannelly 2024-03-03 14:59:02 +11:00 committed by Alexander Kalenik
parent 4a3680cafc
commit 9165faca5e
27 changed files with 353 additions and 105 deletions

View file

@ -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) const = 0;
virtual void paint(PaintContext& context, DevicePixelRect const& dest_rect, ImageRendering, Vector<Gfx::Path> const& clip_paths = {}) const = 0;
virtual Optional<Gfx::Color> color_if_single_pixel_bitmap() const { return {}; }
};

View file

@ -42,10 +42,10 @@ 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) const
void ConicGradientStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering, Vector<Gfx::Path> const& clip_paths) const
{
VERIFY(m_resolved.has_value());
Painting::paint_conic_gradient(context, dest_rect, m_resolved->data, context.rounded_device_point(m_resolved->position));
Painting::paint_conic_gradient(context, dest_rect, m_resolved->data, context.rounded_device_point(m_resolved->position), clip_paths);
}
bool ConicGradientStyleValue::equals(StyleValue const& other) const

View file

@ -25,7 +25,7 @@ public:
virtual String to_string() const override;
void paint(PaintContext&, DevicePixelRect const& dest_rect, CSS::ImageRendering) const override;
void paint(PaintContext&, DevicePixelRect const& dest_rect, CSS::ImageRendering, Vector<Gfx::Path> const& clip_paths = {}) const override;
virtual bool equals(StyleValue const& other) const override;

View file

@ -131,11 +131,11 @@ Optional<CSSPixelFraction> ImageStyleValue::natural_aspect_ratio() const
return {};
}
void ImageStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering) const
void ImageStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering, Vector<Gfx::Path> const& clip_paths) const
{
if (auto const* b = bitmap(m_current_frame_index, dest_rect.size().to_type<int>()); b != nullptr) {
auto scaling_mode = to_gfx_scaling_mode(image_rendering, b->rect(), dest_rect.to_type<int>());
context.recording_painter().draw_scaled_immutable_bitmap(dest_rect.to_type<int>(), *b, b->rect(), scaling_mode);
context.recording_painter().draw_scaled_immutable_bitmap(dest_rect.to_type<int>(), *b, b->rect(), scaling_mode, clip_paths);
}
}

View file

@ -45,7 +45,7 @@ public:
Optional<CSSPixelFraction> natural_aspect_ratio() const override;
virtual bool is_paintable() const override;
void paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering) const override;
void paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering, Vector<Gfx::Path> const& clip_paths = {}) const override;
virtual Optional<Gfx::Color> color_if_single_pixel_bitmap() const override;

View file

@ -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) const
void LinearGradientStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering, Vector<Gfx::Path> const& clip_paths) const
{
VERIFY(m_resolved.has_value());
Painting::paint_linear_gradient(context, dest_rect, m_resolved->data);
Painting::paint_linear_gradient(context, dest_rect, m_resolved->data, clip_paths);
}
}

View file

@ -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) const override;
void paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering, Vector<Gfx::Path> const& clip_paths = {}) const override;
private:
LinearGradientStyleValue(GradientDirection direction, Vector<LinearColorStopListElement> color_stop_list, GradientType type, GradientRepeating repeating)

View file

@ -207,12 +207,13 @@ 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) const
void RadialGradientStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering, Vector<Gfx::Path> const& clip_paths) const
{
VERIFY(m_resolved.has_value());
Painting::paint_radial_gradient(context, dest_rect, m_resolved->data,
context.rounded_device_point(m_resolved->center),
context.rounded_device_size(m_resolved->gradient_size));
context.rounded_device_size(m_resolved->gradient_size),
clip_paths);
}
}

View file

@ -51,7 +51,7 @@ public:
virtual String to_string() const override;
void paint(PaintContext&, DevicePixelRect const& dest_rect, CSS::ImageRendering) const override;
void paint(PaintContext&, DevicePixelRect const& dest_rect, CSS::ImageRendering, Vector<Gfx::Path> const& clip_paths = {}) const override;
virtual bool equals(StyleValue const& other) const override;