diff --git a/Tests/LibWeb/Ref/inline-paintable-background-clip-text.html b/Tests/LibWeb/Ref/inline-paintable-background-clip-text.html
new file mode 100644
index 00000000000..fd0aca62158
--- /dev/null
+++ b/Tests/LibWeb/Ref/inline-paintable-background-clip-text.html
@@ -0,0 +1,11 @@
+
+
+
+Hello
diff --git a/Tests/LibWeb/Ref/reference/inline-paintable-background-clip-text-ref.html b/Tests/LibWeb/Ref/reference/inline-paintable-background-clip-text-ref.html
new file mode 100644
index 00000000000..c1ff4f0bf6f
--- /dev/null
+++ b/Tests/LibWeb/Ref/reference/inline-paintable-background-clip-text-ref.html
@@ -0,0 +1,10 @@
+
+
+
Hello
diff --git a/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp b/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp
index de24a0f5562..d788d57cc56 100644
--- a/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp
+++ b/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp
@@ -7,14 +7,11 @@
*/
#include
+#include
#include
#include
#include
-#include
-#include
-#include
-#include
-#include
+#include
namespace Web::Painting {
@@ -60,9 +57,74 @@ static CSSPixelSize run_default_sizing_algorithm(
return default_size;
}
-// 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 const& clip_paths)
+static Vector compute_text_clip_paths(PaintContext& context, Paintable const& paintable)
{
+ Vector text_clip_paths;
+ auto add_text_clip_path = [&](PaintableFragment const& fragment) {
+ // Scale to the device pixels.
+ Gfx::Path glyph_run_path;
+ for (auto glyph : fragment.glyph_run().glyphs()) {
+ glyph.visit([&](auto& glyph) {
+ glyph.font = *glyph.font->with_size(glyph.font->point_size() * static_cast(context.device_pixels_per_css_pixel()));
+ 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 const& scaled_font = static_cast(*draw_glyph.font);
+ 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));
+ };
+
+ paintable.for_each_in_inclusive_subtree([&](auto& paintable) {
+ if (is(paintable)) {
+ auto const& paintable_lines = static_cast(paintable);
+ for (auto const& fragment : paintable_lines.fragments()) {
+ if (is(fragment.layout_node()))
+ add_text_clip_path(fragment);
+ }
+ } else if (is(paintable)) {
+ auto const& inline_paintable = static_cast(paintable);
+ for (auto const& fragment : inline_paintable.fragments()) {
+ if (is(fragment.layout_node()))
+ add_text_clip_path(fragment);
+ }
+ }
+ return TraversalDecision::Continue;
+ });
+
+ return text_clip_paths;
+}
+
+// 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 {};
+ if (background_layers && !background_layers->is_empty() && background_layers->last().clip == CSS::BackgroundBox::Text) {
+ clip_paths = compute_text_clip_paths(context, *layout_node.paintable());
+ }
+
auto& painter = context.recording_painter();
struct BackgroundBox {
diff --git a/Userland/Libraries/LibWeb/Painting/BackgroundPainting.h b/Userland/Libraries/LibWeb/Painting/BackgroundPainting.h
index 8da6a9240c6..32c5fbad409 100644
--- a/Userland/Libraries/LibWeb/Painting/BackgroundPainting.h
+++ b/Userland/Libraries/LibWeb/Painting/BackgroundPainting.h
@@ -12,6 +12,6 @@
namespace Web::Painting {
-void paint_background(PaintContext&, Layout::NodeWithStyleAndBoxModelMetrics const&, CSSPixelRect const&, Color background_color, CSS::ImageRendering, Vector const*, BorderRadiiData const&, Vector const& clip_paths = {});
+void paint_background(PaintContext&, Layout::NodeWithStyleAndBoxModelMetrics const&, CSSPixelRect const&, Color background_color, CSS::ImageRendering, Vector const*, BorderRadiiData const&);
}
diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp
index 09ee1f2a6c5..e1d254110a2 100644
--- a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp
+++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp
@@ -478,72 +478,7 @@ void PaintableBox::paint_background(PaintContext& context) const
if (computed_values().border_top().width != 0 || computed_values().border_right().width != 0 || computed_values().border_bottom().width != 0 || computed_values().border_left().width != 0)
background_rect = absolute_border_box_rect();
- Vector text_clip_paths {};
- if (background_layers && !background_layers->is_empty() && background_layers->last().clip == CSS::BackgroundBox::Text) {
- text_clip_paths = compute_text_clip_paths(context);
- }
-
- Painting::paint_background(context, layout_box(), background_rect, background_color, computed_values().image_rendering(), background_layers, normalized_border_radii_data(), text_clip_paths);
-}
-
-Vector PaintableBox::compute_text_clip_paths(PaintContext& context) const
-{
- Vector text_clip_paths;
- auto add_text_clip_path = [&](PaintableFragment const& fragment) {
- // Scale to the device pixels.
- Gfx::Path glyph_run_path;
- for (auto glyph : fragment.glyph_run().glyphs()) {
- glyph.visit([&](auto& glyph) {
- glyph.font = *glyph.font->with_size(glyph.font->point_size() * static_cast(context.device_pixels_per_css_pixel()));
- 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 const& scaled_font = static_cast(*draw_glyph.font);
- 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));
- };
-
- for_each_in_inclusive_subtree([&](auto& paintable) {
- if (is(paintable)) {
- auto const& paintable_lines = static_cast(paintable);
- for (auto const& fragment : paintable_lines.fragments()) {
- if (is(fragment.layout_node()))
- add_text_clip_path(fragment);
- }
- } else if (is(paintable)) {
- auto const& inline_paintable = static_cast(paintable);
- for (auto const& fragment : inline_paintable.fragments()) {
- if (is(fragment.layout_node()))
- add_text_clip_path(fragment);
- }
- }
- return TraversalDecision::Continue;
- });
-
- return text_clip_paths;
+ Painting::paint_background(context, layout_box(), background_rect, background_color, computed_values().image_rendering(), background_layers, normalized_border_radii_data());
}
void PaintableBox::paint_box_shadow(PaintContext& context) const
diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.h b/Userland/Libraries/LibWeb/Painting/PaintableBox.h
index 82c0dab16f2..974fe48e36a 100644
--- a/Userland/Libraries/LibWeb/Painting/PaintableBox.h
+++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.h
@@ -227,8 +227,6 @@ protected:
virtual CSSPixelRect compute_absolute_paint_rect() const;
private:
- Vector compute_text_clip_paths(PaintContext&) const;
-
[[nodiscard]] virtual bool is_paintable_box() const final { return true; }
enum class ScrollDirection {