LibWeb: Save "background-clip: text" mask as a nested display list

Before this change, "background-clip: text" was implemented by saving a
Vector<Gfx::Path> of all glyphs needed to paint a mask for the
background. The issue with this approach was that once glyphs were
extracted into vector paths, the glyph rasterization cache could no
longer be utilized.

With this change, all text required for mask painting is saved in a
nested display list and rasterized as a regular text.
This commit is contained in:
Aliaksandr Kalenik 2024-07-24 22:03:19 +03:00 committed by Andreas Kling
parent 50ab5642cc
commit 67d68eac64
Notes: github-actions[bot] 2024-07-25 12:34:36 +00:00
17 changed files with 102 additions and 102 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 KiB

After

Width:  |  Height:  |  Size: 267 KiB

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

View File

@ -42,12 +42,12 @@ 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, Vector<Gfx::Path> const& clip_paths) const
void ConicGradientStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering, RefPtr<Painting::DisplayList> text_clip) const
{
VERIFY(m_resolved.has_value());
auto destination_rect = dest_rect.to_type<int>();
auto position = context.rounded_device_point(m_resolved->position).to_type<int>();
context.display_list_recorder().fill_rect_with_conic_gradient(destination_rect, m_resolved->data, position, clip_paths);
context.display_list_recorder().fill_rect_with_conic_gradient(destination_rect, m_resolved->data, position, text_clip);
}
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, Vector<Gfx::Path> const& clip_paths = {}) const override;
void paint(PaintContext&, DevicePixelRect const& dest_rect, CSS::ImageRendering, RefPtr<Painting::DisplayList> text_clip = {}) const override;
virtual bool equals(StyleValue const& other) const override;

View File

@ -133,11 +133,11 @@ Optional<CSSPixelFraction> ImageStyleValue::natural_aspect_ratio() const
return {};
}
void ImageStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering, Vector<Gfx::Path> const& clip_paths) const
void ImageStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering, RefPtr<Painting::DisplayList> text_clip) 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.display_list_recorder().draw_scaled_immutable_bitmap(dest_rect.to_type<int>(), *b, b->rect(), scaling_mode, clip_paths);
context.display_list_recorder().draw_scaled_immutable_bitmap(dest_rect.to_type<int>(), *b, b->rect(), scaling_mode, text_clip);
}
}

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, Vector<Gfx::Path> const& clip_paths = {}) const override;
void paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering, RefPtr<Painting::DisplayList> clip_paths = {}) const override;
virtual Optional<Gfx::Color> color_if_single_pixel_bitmap() const override;
Gfx::ImmutableBitmap const* current_frame_bitmap(DevicePixelRect const& dest_rect) const;

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

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

View File

@ -207,12 +207,12 @@ 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, Vector<Gfx::Path> const& clip_paths) const
void RadialGradientStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering, RefPtr<Painting::DisplayList> text_clip) const
{
VERIFY(m_resolved.has_value());
auto center = context.rounded_device_point(m_resolved->center).to_type<int>();
auto size = context.rounded_device_size(m_resolved->gradient_size).to_type<int>();
context.display_list_recorder().fill_rect_with_radial_gradient(dest_rect.to_type<int>(), m_resolved->data, center, size, clip_paths);
context.display_list_recorder().fill_rect_with_radial_gradient(dest_rect.to_type<int>(), m_resolved->data, center, size, text_clip);
}
}

View File

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

View File

@ -25,6 +25,7 @@ class XMLDocumentBuilder;
namespace Web::Painting {
class BackingStore;
class DisplayList;
class DisplayListRecorder;
class SVGGradientPaintStyle;
using PaintStyle = RefPtr<SVGGradientPaintStyle>;

View File

@ -58,47 +58,21 @@ static CSSPixelSize run_default_sizing_algorithm(
return default_size;
}
static Vector<Gfx::Path> compute_text_clip_paths(PaintContext& context, Paintable const& paintable)
static RefPtr<DisplayList> compute_text_clip_paths(PaintContext& context, Paintable const& paintable)
{
Vector<Gfx::Path> text_clip_paths;
auto text_clip_paths = DisplayList::create();
DisplayListRecorder display_list_recorder(*text_clip_paths);
auto add_text_clip_path = [&](PaintableFragment const& fragment) {
auto glyph_run = fragment.glyph_run();
if (!glyph_run || glyph_run->glyphs().is_empty())
return;
// Scale to the device pixels.
Gfx::Path glyph_run_path;
auto const& font = fragment.glyph_run()->font();
auto scaled_font = font.with_size(font.point_size() * static_cast<float>(context.device_pixels_per_css_pixel()));
for (auto glyph : fragment.glyph_run()->glyphs()) {
glyph.visit([&](auto& glyph) {
glyph.position = glyph.position.scaled(context.device_pixels_per_css_pixel());
});
if (glyph.has<Gfx::DrawGlyph>()) {
auto const& draw_glyph = glyph.get<Gfx::DrawGlyph>();
// Get the path for the glyph.
Gfx::Path glyph_path;
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<float>());
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<int>().to_type<float>());
text_clip_paths.append(glyph_run_path.copy_transformed(transform));
DevicePixelPoint baseline_start { fragment_absolute_device_rect.x(), fragment_absolute_device_rect.y() + context.rounded_device_pixels(fragment.baseline()) };
auto scale = context.device_pixels_per_css_pixel();
display_list_recorder.draw_text_run(baseline_start.to_type<int>(), *glyph_run, Gfx::Color::Black, fragment_absolute_device_rect.to_type<int>(), scale);
};
paintable.for_each_in_inclusive_subtree([&](auto& paintable) {
@ -124,9 +98,9 @@ static Vector<Gfx::Path> compute_text_clip_paths(PaintContext& context, Paintabl
// 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<CSS::BackgroundLayerData> const* background_layers, BorderRadiiData const& border_radii)
{
Vector<Gfx::Path> clip_paths {};
RefPtr<DisplayList> text_clip;
if (background_layers && !background_layers->is_empty() && background_layers->last().clip == CSS::BackgroundBox::Text) {
clip_paths = compute_text_clip_paths(context, *layout_node.paintable());
text_clip = compute_text_clip_paths(context, *layout_node.paintable());
}
auto& display_list_recorder = context.display_list_recorder();
@ -191,7 +165,7 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
color_box.radii.top_right.as_corner(context),
color_box.radii.bottom_right.as_corner(context),
color_box.radii.bottom_left.as_corner(context),
clip_paths);
text_clip);
if (!has_paintable_layers)
return;
@ -459,17 +433,17 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
fill_rect = fill_rect->united(image_device_rect);
}
});
display_list_recorder.fill_rect(fill_rect->to_type<int>(), color.value(), clip_paths);
display_list_recorder.fill_rect(fill_rect->to_type<int>(), color.value(), text_clip);
} else if (is<CSS::ImageStyleValue>(image) && repeat_x && repeat_y && !repeat_x_has_gap && !repeat_y_has_gap) {
// Use a dedicated painting command for repeated images instead of recording a separate command for each instance
// of a repeated background, so the painter has the opportunity to optimize the painting of repeated images.
auto dest_rect = context.rounded_device_rect(image_rect);
auto const* bitmap = static_cast<CSS::ImageStyleValue const&>(image).current_frame_bitmap(dest_rect);
auto scaling_mode = to_gfx_scaling_mode(image_rendering, bitmap->rect(), dest_rect.to_type<int>());
context.display_list_recorder().draw_repeated_immutable_bitmap(dest_rect.to_type<int>(), *bitmap, scaling_mode, { .x = repeat_x, .y = repeat_y }, clip_paths);
context.display_list_recorder().draw_repeated_immutable_bitmap(dest_rect.to_type<int>(), clip_rect.to_type<int>(), *bitmap, scaling_mode, { .x = repeat_x, .y = repeat_y }, text_clip);
} else {
for_each_image_device_rect([&](auto const& image_device_rect) {
image.paint(context, image_device_rect, image_rendering, clip_paths);
image.paint(context, image_device_rect, image_rendering, text_clip);
});
}
}

View File

@ -33,6 +33,8 @@
namespace Web::Painting {
class DisplayList;
struct DrawGlyphRun {
NonnullRefPtr<Gfx::GlyphRun> glyph_run;
Color color;
@ -48,7 +50,7 @@ struct DrawGlyphRun {
struct FillRect {
Gfx::IntRect rect;
Color color;
Vector<Gfx::Path> clip_paths;
RefPtr<DisplayList> text_clip;
[[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; }
void translate_by(Gfx::IntPoint const& offset) { rect.translate_by(offset); }
@ -69,7 +71,7 @@ struct DrawScaledImmutableBitmap {
NonnullRefPtr<Gfx::ImmutableBitmap> bitmap;
Gfx::IntRect src_rect;
Gfx::ScalingMode scaling_mode;
Vector<Gfx::Path> clip_paths;
RefPtr<DisplayList> text_clip;
[[nodiscard]] Gfx::IntRect bounding_rect() const { return dst_rect; }
void translate_by(Gfx::IntPoint const& offset) { dst_rect.translate_by(offset); }
@ -82,10 +84,11 @@ struct DrawRepeatedImmutableBitmap {
};
Gfx::IntRect dst_rect;
Gfx::IntRect clip_rect;
NonnullRefPtr<Gfx::ImmutableBitmap> bitmap;
Gfx::ScalingMode scaling_mode;
Repeat repeat;
Vector<Gfx::Path> clip_paths;
RefPtr<DisplayList> text_clip;
void translate_by(Gfx::IntPoint const& offset) { dst_rect.translate_by(offset); }
};
@ -129,7 +132,7 @@ struct PopStackingContext { };
struct PaintLinearGradient {
Gfx::IntRect gradient_rect;
LinearGradientData linear_gradient_data;
Vector<Gfx::Path> clip_paths;
RefPtr<DisplayList> text_clip;
[[nodiscard]] Gfx::IntRect bounding_rect() const { return gradient_rect; }
@ -170,7 +173,7 @@ struct FillRectWithRoundedCorners {
Gfx::IntRect rect;
Color color;
CornerRadii corner_radii;
Vector<Gfx::Path> clip_paths;
RefPtr<DisplayList> text_clip;
[[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; }
void translate_by(Gfx::IntPoint const& offset) { rect.translate_by(offset); }
@ -310,7 +313,7 @@ struct PaintRadialGradient {
RadialGradientData radial_gradient_data;
Gfx::IntPoint center;
Gfx::IntSize size;
Vector<Gfx::Path> clip_paths;
RefPtr<DisplayList> text_clip;
[[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; }
@ -321,7 +324,7 @@ struct PaintConicGradient {
Gfx::IntRect rect;
ConicGradientData conic_gradient_data;
Gfx::IntPoint position;
Vector<Gfx::Path> clip_paths;
RefPtr<DisplayList> text_clip;
[[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; }

View File

@ -62,6 +62,11 @@ public:
m_surface->readPixels(pixmap, 0, 0);
}
sk_sp<SkSurface> make_surface(int width, int height)
{
return m_surface->makeSurface(width, height);
}
private:
sk_sp<SkSurface> m_surface;
};
@ -368,17 +373,13 @@ static SkSamplingOptions to_skia_sampling_options(Gfx::ScalingMode scaling_mode)
}
}
#define APPLY_PATH_CLIP_IF_NEEDED \
ScopeGuard restore_path_clip { [&] { \
if (command.clip_paths.size() > 0) \
surface().canvas().restore(); \
} }; \
if (command.clip_paths.size() > 0) { \
surface().canvas().save(); \
SkPath clip_path; \
for (auto const& path : command.clip_paths) \
clip_path.addPath(to_skia_path(path)); \
surface().canvas().clipPath(clip_path, true); \
#define APPLY_TEXT_CLIP_IF_NEEDED(MASK_RECT) \
ScopeGuard const restore { [&] { \
if (command.text_clip) \
surface().canvas().restore(); \
} }; \
if (command.text_clip) { \
apply_mask_painted_from(*command.text_clip, MASK_RECT); \
}
DisplayListPlayerSkia::SkiaSurface& DisplayListPlayerSkia::surface() const
@ -422,7 +423,7 @@ void DisplayListPlayerSkia::draw_glyph_run(DrawGlyphRun const& command)
void DisplayListPlayerSkia::fill_rect(FillRect const& command)
{
APPLY_PATH_CLIP_IF_NEEDED
APPLY_TEXT_CLIP_IF_NEEDED(command.rect)
auto const& rect = command.rect;
auto& canvas = surface().canvas();
@ -444,7 +445,7 @@ void DisplayListPlayerSkia::draw_scaled_bitmap(DrawScaledBitmap const& command)
void DisplayListPlayerSkia::draw_scaled_immutable_bitmap(DrawScaledImmutableBitmap const& command)
{
APPLY_PATH_CLIP_IF_NEEDED
APPLY_TEXT_CLIP_IF_NEEDED(command.dst_rect)
auto src_rect = to_skia_rect(command.src_rect);
auto dst_rect = to_skia_rect(command.dst_rect);
@ -457,7 +458,7 @@ void DisplayListPlayerSkia::draw_scaled_immutable_bitmap(DrawScaledImmutableBitm
void DisplayListPlayerSkia::draw_repeated_immutable_bitmap(DrawRepeatedImmutableBitmap const& command)
{
APPLY_PATH_CLIP_IF_NEEDED
APPLY_TEXT_CLIP_IF_NEEDED(command.clip_rect)
auto bitmap = to_skia_bitmap(command.bitmap->bitmap());
auto image = SkImages::RasterFromBitmap(bitmap);
@ -655,7 +656,7 @@ static ColorStopList expand_repeat_length(ColorStopList const& color_stop_list,
void DisplayListPlayerSkia::paint_linear_gradient(PaintLinearGradient const& command)
{
APPLY_PATH_CLIP_IF_NEEDED
APPLY_TEXT_CLIP_IF_NEEDED(command.gradient_rect)
auto const& linear_gradient_data = command.linear_gradient_data;
auto color_stop_list = linear_gradient_data.color_stops.list;
@ -833,7 +834,7 @@ void DisplayListPlayerSkia::paint_text_shadow(PaintTextShadow const& command)
void DisplayListPlayerSkia::fill_rect_with_rounded_corners(FillRectWithRoundedCorners const& command)
{
APPLY_PATH_CLIP_IF_NEEDED
APPLY_TEXT_CLIP_IF_NEEDED(command.rect)
auto const& rect = command.rect;
@ -1200,7 +1201,7 @@ void DisplayListPlayerSkia::draw_rect(DrawRect const& command)
void DisplayListPlayerSkia::paint_radial_gradient(PaintRadialGradient const& command)
{
APPLY_PATH_CLIP_IF_NEEDED
APPLY_TEXT_CLIP_IF_NEEDED(command.rect)
auto const& radial_gradient_data = command.radial_gradient_data;
@ -1249,7 +1250,7 @@ void DisplayListPlayerSkia::paint_radial_gradient(PaintRadialGradient const& com
void DisplayListPlayerSkia::paint_conic_gradient(PaintConicGradient const& command)
{
APPLY_PATH_CLIP_IF_NEEDED
APPLY_TEXT_CLIP_IF_NEEDED(command.rect)
auto const& conic_gradient_data = command.conic_gradient_data;
@ -1312,4 +1313,22 @@ bool DisplayListPlayerSkia::would_be_fully_clipped_by_painter(Gfx::IntRect rect)
return surface().canvas().quickReject(to_skia_rect(rect));
}
void DisplayListPlayerSkia::apply_mask_painted_from(DisplayList& display_list, Gfx::IntRect rect)
{
auto mask_surface = m_surface->make_surface(rect.width(), rect.height());
auto previous_surface = move(m_surface);
m_surface = make<SkiaSurface>(mask_surface);
surface().canvas().translate(-rect.x(), -rect.y());
execute(display_list);
m_surface = move(previous_surface);
SkMatrix mask_matrix;
mask_matrix.setTranslate(rect.x(), rect.y());
auto image = mask_surface->makeImageSnapshot();
auto shader = image->makeShader(SkSamplingOptions(), mask_matrix);
surface().canvas().save();
surface().canvas().clipShader(shader);
}
}

View File

@ -80,6 +80,8 @@ private:
bool would_be_fully_clipped_by_painter(Gfx::IntRect) const override;
void apply_mask_painted_from(DisplayList&, Gfx::IntRect);
class SkiaSurface;
SkiaSurface& surface() const;

View File

@ -42,14 +42,14 @@ void DisplayListRecorder::blit_corner_clipping(u32 id)
append(BlitCornerClipping { id, state().translation.map(clip_state.rect) });
}
void DisplayListRecorder::fill_rect(Gfx::IntRect const& rect, Color color, Vector<Gfx::Path> const& clip_paths)
void DisplayListRecorder::fill_rect(Gfx::IntRect const& rect, Color color, RefPtr<DisplayList> text_clip)
{
if (rect.is_empty())
return;
append(FillRect {
.rect = state().translation.map(rect),
.color = color,
.clip_paths = clip_paths,
.text_clip = move(text_clip),
});
}
@ -140,17 +140,17 @@ void DisplayListRecorder::fill_ellipse(Gfx::IntRect const& a_rect, Color color)
});
}
void DisplayListRecorder::fill_rect_with_linear_gradient(Gfx::IntRect const& gradient_rect, LinearGradientData const& data, Vector<Gfx::Path> const& clip_paths)
void DisplayListRecorder::fill_rect_with_linear_gradient(Gfx::IntRect const& gradient_rect, LinearGradientData const& data, RefPtr<DisplayList> text_clip)
{
if (gradient_rect.is_empty())
return;
append(PaintLinearGradient {
.gradient_rect = state().translation.map(gradient_rect),
.linear_gradient_data = data,
.clip_paths = clip_paths });
.text_clip = text_clip });
}
void DisplayListRecorder::fill_rect_with_conic_gradient(Gfx::IntRect const& rect, ConicGradientData const& data, Gfx::IntPoint const& position, Vector<Gfx::Path> const& clip_paths)
void DisplayListRecorder::fill_rect_with_conic_gradient(Gfx::IntRect const& rect, ConicGradientData const& data, Gfx::IntPoint const& position, RefPtr<DisplayList> text_clip)
{
if (rect.is_empty())
return;
@ -158,10 +158,10 @@ void DisplayListRecorder::fill_rect_with_conic_gradient(Gfx::IntRect const& rect
.rect = state().translation.map(rect),
.conic_gradient_data = data,
.position = position,
.clip_paths = clip_paths });
.text_clip = text_clip });
}
void DisplayListRecorder::fill_rect_with_radial_gradient(Gfx::IntRect const& rect, RadialGradientData const& data, Gfx::IntPoint center, Gfx::IntSize size, Vector<Gfx::Path> const& clip_paths)
void DisplayListRecorder::fill_rect_with_radial_gradient(Gfx::IntRect const& rect, RadialGradientData const& data, Gfx::IntPoint center, Gfx::IntSize size, RefPtr<DisplayList> text_clip)
{
if (rect.is_empty())
return;
@ -170,7 +170,7 @@ void DisplayListRecorder::fill_rect_with_radial_gradient(Gfx::IntRect const& rec
.radial_gradient_data = data,
.center = center,
.size = size,
.clip_paths = clip_paths });
.text_clip = text_clip });
}
void DisplayListRecorder::draw_rect(Gfx::IntRect const& rect, Color color, bool rough)
@ -195,7 +195,7 @@ void DisplayListRecorder::draw_scaled_bitmap(Gfx::IntRect const& dst_rect, Gfx::
});
}
void DisplayListRecorder::draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode, Vector<Gfx::Path> const& clip_paths)
void DisplayListRecorder::draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode, RefPtr<DisplayList> text_clip)
{
if (dst_rect.is_empty())
return;
@ -204,18 +204,19 @@ void DisplayListRecorder::draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_r
.bitmap = bitmap,
.src_rect = src_rect,
.scaling_mode = scaling_mode,
.clip_paths = clip_paths,
.text_clip = move(text_clip),
});
}
void DisplayListRecorder::draw_repeated_immutable_bitmap(Gfx::IntRect dst_rect, NonnullRefPtr<Gfx::ImmutableBitmap> bitmap, Gfx::ScalingMode scaling_mode, DrawRepeatedImmutableBitmap::Repeat repeat, Vector<Gfx::Path> const& clip_paths)
void DisplayListRecorder::draw_repeated_immutable_bitmap(Gfx::IntRect dst_rect, Gfx::IntRect clip_rect, NonnullRefPtr<Gfx::ImmutableBitmap> bitmap, Gfx::ScalingMode scaling_mode, DrawRepeatedImmutableBitmap::Repeat repeat, RefPtr<DisplayList> text_clip)
{
append(DrawRepeatedImmutableBitmap {
.dst_rect = dst_rect,
.clip_rect = clip_rect,
.bitmap = move(bitmap),
.scaling_mode = scaling_mode,
.repeat = repeat,
.clip_paths = clip_paths,
.text_clip = move(text_clip),
});
}
@ -363,7 +364,7 @@ void DisplayListRecorder::paint_text_shadow(int blur_radius, Gfx::IntRect boundi
.draw_location = state().translation.map(draw_location) });
}
void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& rect, Color color, Gfx::AntiAliasingPainter::CornerRadius top_left_radius, Gfx::AntiAliasingPainter::CornerRadius top_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_left_radius, Vector<Gfx::Path> const& clip_paths)
void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& rect, Color color, Gfx::AntiAliasingPainter::CornerRadius top_left_radius, Gfx::AntiAliasingPainter::CornerRadius top_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_left_radius, RefPtr<DisplayList> clip_paths)
{
if (rect.is_empty())
return;
@ -382,18 +383,18 @@ void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& rec
.bottom_right = bottom_right_radius,
.bottom_left = bottom_left_radius,
},
.clip_paths = clip_paths,
.text_clip = clip_paths,
});
}
void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int radius, Vector<Gfx::Path> const& clip_paths)
void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int radius, RefPtr<DisplayList> clip_paths)
{
if (a_rect.is_empty())
return;
fill_rect_with_rounded_corners(a_rect, color, radius, radius, radius, radius, clip_paths);
fill_rect_with_rounded_corners(a_rect, color, radius, radius, radius, radius, move(clip_paths));
}
void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int top_left_radius, int top_right_radius, int bottom_right_radius, int bottom_left_radius, Vector<Gfx::Path> const& clip_paths)
void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int top_left_radius, int top_right_radius, int bottom_right_radius, int bottom_left_radius, RefPtr<DisplayList> clip_paths)
{
if (a_rect.is_empty())
return;

View File

@ -40,7 +40,7 @@ class DisplayListRecorder {
AK_MAKE_NONMOVABLE(DisplayListRecorder);
public:
void fill_rect(Gfx::IntRect const& rect, Color color, Vector<Gfx::Path> const& clip_paths = {});
void fill_rect(Gfx::IntRect const& rect, Color color, RefPtr<DisplayList> text_clip = {});
struct FillPathUsingColorParams {
Gfx::Path path;
@ -80,16 +80,16 @@ public:
void fill_ellipse(Gfx::IntRect const& a_rect, Color color);
void fill_rect_with_linear_gradient(Gfx::IntRect const& gradient_rect, LinearGradientData const& data, Vector<Gfx::Path> const& clip_paths = {});
void fill_rect_with_conic_gradient(Gfx::IntRect const& rect, ConicGradientData const& data, Gfx::IntPoint const& position, Vector<Gfx::Path> const& clip_paths = {});
void fill_rect_with_radial_gradient(Gfx::IntRect const& rect, RadialGradientData const& data, Gfx::IntPoint center, Gfx::IntSize size, Vector<Gfx::Path> const& clip_paths = {});
void fill_rect_with_linear_gradient(Gfx::IntRect const& gradient_rect, LinearGradientData const& data, RefPtr<DisplayList> text_clip = {});
void fill_rect_with_conic_gradient(Gfx::IntRect const& rect, ConicGradientData const& data, Gfx::IntPoint const& position, RefPtr<DisplayList> text_clip = {});
void fill_rect_with_radial_gradient(Gfx::IntRect const& rect, RadialGradientData const& data, Gfx::IntPoint center, Gfx::IntSize size, RefPtr<DisplayList> text_clip = {});
void draw_rect(Gfx::IntRect const& rect, Color color, bool rough = false);
void draw_scaled_bitmap(Gfx::IntRect const& dst_rect, Gfx::Bitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode = Gfx::ScalingMode::NearestNeighbor);
void draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode = Gfx::ScalingMode::NearestNeighbor, Vector<Gfx::Path> const& clip_paths = {});
void draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode = Gfx::ScalingMode::NearestNeighbor, RefPtr<DisplayList> text_clip = {});
void draw_repeated_immutable_bitmap(Gfx::IntRect dst_rect, NonnullRefPtr<Gfx::ImmutableBitmap> bitmap, Gfx::ScalingMode scaling_mode, DrawRepeatedImmutableBitmap::Repeat, Vector<Gfx::Path> const& clip_paths = {});
void draw_repeated_immutable_bitmap(Gfx::IntRect dst_rect, Gfx::IntRect clip_rect, NonnullRefPtr<Gfx::ImmutableBitmap> bitmap, Gfx::ScalingMode scaling_mode, DrawRepeatedImmutableBitmap::Repeat, RefPtr<DisplayList> text_clip = {});
void draw_line(Gfx::IntPoint from, Gfx::IntPoint to, Color color, int thickness = 1, Gfx::LineStyle style = Gfx::LineStyle::Solid, Color alternate_color = Color::Transparent);
@ -131,9 +131,9 @@ public:
void paint_inner_box_shadow_params(PaintBoxShadowParams params);
void paint_text_shadow(int blur_radius, Gfx::IntRect bounding_rect, Gfx::IntRect text_rect, Gfx::GlyphRun const&, double glyph_run_scale, Color color, Gfx::IntPoint draw_location);
void fill_rect_with_rounded_corners(Gfx::IntRect const& rect, Color color, Gfx::AntiAliasingPainter::CornerRadius top_left_radius, Gfx::AntiAliasingPainter::CornerRadius top_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_left_radius, Vector<Gfx::Path> const& clip_paths = {});
void fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int radius, Vector<Gfx::Path> const& clip_paths = {});
void fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int top_left_radius, int top_right_radius, int bottom_right_radius, int bottom_left_radius, Vector<Gfx::Path> const& clip_paths = {});
void fill_rect_with_rounded_corners(Gfx::IntRect const& rect, Color color, Gfx::AntiAliasingPainter::CornerRadius top_left_radius, Gfx::AntiAliasingPainter::CornerRadius top_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_left_radius, RefPtr<DisplayList> text_clip = {});
void fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int radius, RefPtr<DisplayList> text_clip = {});
void fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int top_left_radius, int top_right_radius, int bottom_right_radius, int bottom_left_radius, RefPtr<DisplayList> text_clip = {});
void draw_triangle_wave(Gfx::IntPoint a_p1, Gfx::IntPoint a_p2, Color color, int amplitude, int thickness);