LibGfx: Move Gfx::Painter::WindingRule => Gfx::WindingRule

This commit is contained in:
Andreas Kling 2024-06-05 10:21:28 +02:00 committed by Andreas Kling
commit 57906a4e1b
Notes: sideshowbarker 2024-07-17 01:53:23 +09:00
16 changed files with 68 additions and 55 deletions

View file

@ -9,6 +9,7 @@
#include <LibGfx/Painter.h> #include <LibGfx/Painter.h>
#include <LibGfx/Path.h> #include <LibGfx/Path.h>
#include <LibGfx/Quad.h> #include <LibGfx/Quad.h>
#include <LibGfx/WindingRule.h>
namespace Gfx { namespace Gfx {
@ -33,8 +34,8 @@ public:
draw_line(line.a(), line.b(), color, thickness, style, alternate_color, line_length_mode); draw_line(line.a(), line.b(), color, thickness, style, alternate_color, line_length_mode);
} }
void fill_path(Path const&, Color, Painter::WindingRule rule = Painter::WindingRule::Nonzero); void fill_path(Path const&, Color, WindingRule rule = WindingRule::Nonzero);
void fill_path(Path const&, PaintStyle const& paint_style, float opacity = 1.0f, Painter::WindingRule rule = Painter::WindingRule::Nonzero); void fill_path(Path const&, PaintStyle const& paint_style, float opacity = 1.0f, WindingRule rule = WindingRule::Nonzero);
void stroke_path(Path const&, Color, float thickness); void stroke_path(Path const&, Color, float thickness);
void stroke_path(Path const&, PaintStyle const& paint_style, float thickness, float opacity = 1.0f); void stroke_path(Path const&, PaintStyle const& paint_style, float thickness, float opacity = 1.0f);

View file

@ -99,13 +99,13 @@ EdgeFlagPathRasterizer<SamplesPerPixel>::EdgeFlagPathRasterizer(IntSize size)
} }
template<unsigned SamplesPerPixel> template<unsigned SamplesPerPixel>
void EdgeFlagPathRasterizer<SamplesPerPixel>::fill(Painter& painter, Path const& path, Color color, Painter::WindingRule winding_rule, FloatPoint offset) void EdgeFlagPathRasterizer<SamplesPerPixel>::fill(Painter& painter, Path const& path, Color color, WindingRule winding_rule, FloatPoint offset)
{ {
fill_internal(painter, path, color, winding_rule, offset); fill_internal(painter, path, color, winding_rule, offset);
} }
template<unsigned SamplesPerPixel> template<unsigned SamplesPerPixel>
void EdgeFlagPathRasterizer<SamplesPerPixel>::fill(Painter& painter, Path const& path, PaintStyle const& style, float opacity, Painter::WindingRule winding_rule, FloatPoint offset) void EdgeFlagPathRasterizer<SamplesPerPixel>::fill(Painter& painter, Path const& path, PaintStyle const& style, float opacity, WindingRule winding_rule, FloatPoint offset)
{ {
style.paint(enclosing_int_rect(path.bounding_box()), [&](PaintStyle::SamplerFunction sampler) { style.paint(enclosing_int_rect(path.bounding_box()), [&](PaintStyle::SamplerFunction sampler) {
if (opacity == 0.0f) if (opacity == 0.0f)
@ -122,7 +122,7 @@ void EdgeFlagPathRasterizer<SamplesPerPixel>::fill(Painter& painter, Path const&
} }
template<unsigned SamplesPerPixel> template<unsigned SamplesPerPixel>
void EdgeFlagPathRasterizer<SamplesPerPixel>::fill_internal(Painter& painter, Path const& path, auto color_or_function, Painter::WindingRule winding_rule, FloatPoint offset) void EdgeFlagPathRasterizer<SamplesPerPixel>::fill_internal(Painter& painter, Path const& path, auto color_or_function, WindingRule winding_rule, FloatPoint offset)
{ {
auto bounding_box = enclosing_int_rect(path.bounding_box().translated(offset)); auto bounding_box = enclosing_int_rect(path.bounding_box().translated(offset));
auto dest_rect = bounding_box.translated(painter.translation()); auto dest_rect = bounding_box.translated(painter.translation());
@ -187,7 +187,7 @@ void EdgeFlagPathRasterizer<SamplesPerPixel>::fill_internal(Painter& painter, Pa
Detail::Edge* active_edges = nullptr; Detail::Edge* active_edges = nullptr;
if (winding_rule == Painter::WindingRule::EvenOdd) { if (winding_rule == WindingRule::EvenOdd) {
auto plot_edge = [&](Detail::Edge& edge, int start_subpixel_y, int end_subpixel_y, EdgeExtent& edge_extent) { auto plot_edge = [&](Detail::Edge& edge, int start_subpixel_y, int end_subpixel_y, EdgeExtent& edge_extent) {
for_each_sample(edge, start_subpixel_y, end_subpixel_y, edge_extent, [&](int xi, int, SampleType sample) { for_each_sample(edge, start_subpixel_y, end_subpixel_y, edge_extent, [&](int xi, int, SampleType sample) {
m_scanline[xi] ^= sample; m_scanline[xi] ^= sample;
@ -196,10 +196,10 @@ void EdgeFlagPathRasterizer<SamplesPerPixel>::fill_internal(Painter& painter, Pa
for (int scanline = min_scanline; scanline <= max_scanline; scanline++) { for (int scanline = min_scanline; scanline <= max_scanline; scanline++) {
auto edge_extent = empty_edge_extent(); auto edge_extent = empty_edge_extent();
active_edges = plot_edges_for_scanline(scanline, plot_edge, edge_extent, active_edges); active_edges = plot_edges_for_scanline(scanline, plot_edge, edge_extent, active_edges);
write_scanline<Painter::WindingRule::EvenOdd>(painter, scanline, edge_extent, color_or_function); write_scanline<WindingRule::EvenOdd>(painter, scanline, edge_extent, color_or_function);
} }
} else { } else {
VERIFY(winding_rule == Painter::WindingRule::Nonzero); VERIFY(winding_rule == WindingRule::Nonzero);
// Only allocate the winding buffer if needed. // Only allocate the winding buffer if needed.
// NOTE: non-zero fills are a fair bit less efficient. So if you can do an even-odd fill do that :^) // NOTE: non-zero fills are a fair bit less efficient. So if you can do an even-odd fill do that :^)
if (m_windings.is_empty()) if (m_windings.is_empty())
@ -214,7 +214,7 @@ void EdgeFlagPathRasterizer<SamplesPerPixel>::fill_internal(Painter& painter, Pa
for (int scanline = min_scanline; scanline <= max_scanline; scanline++) { for (int scanline = min_scanline; scanline <= max_scanline; scanline++) {
auto edge_extent = empty_edge_extent(); auto edge_extent = empty_edge_extent();
active_edges = plot_edges_for_scanline(scanline, plot_edge, edge_extent, active_edges); active_edges = plot_edges_for_scanline(scanline, plot_edge, edge_extent, active_edges);
write_scanline<Painter::WindingRule::Nonzero>(painter, scanline, edge_extent, color_or_function); write_scanline<WindingRule::Nonzero>(painter, scanline, edge_extent, color_or_function);
} }
} }
} }
@ -345,10 +345,10 @@ auto EdgeFlagPathRasterizer<SamplesPerPixel>::accumulate_non_zero_scanline(EdgeE
} }
template<unsigned SamplesPerPixel> template<unsigned SamplesPerPixel>
template<Painter::WindingRule WindingRule, typename Callback> template<WindingRule WindingRule, typename Callback>
auto EdgeFlagPathRasterizer<SamplesPerPixel>::accumulate_scanline(EdgeExtent edge_extent, auto init, Callback callback) auto EdgeFlagPathRasterizer<SamplesPerPixel>::accumulate_scanline(EdgeExtent edge_extent, auto init, Callback callback)
{ {
if constexpr (WindingRule == Painter::WindingRule::EvenOdd) if constexpr (WindingRule == WindingRule::EvenOdd)
return accumulate_even_odd_scanline(edge_extent, init, callback); return accumulate_even_odd_scanline(edge_extent, init, callback);
else else
return accumulate_non_zero_scanline(edge_extent, init, callback); return accumulate_non_zero_scanline(edge_extent, init, callback);
@ -374,7 +374,7 @@ void EdgeFlagPathRasterizer<SamplesPerPixel>::fast_fill_solid_color_span(ARGB32*
} }
template<unsigned SamplesPerPixel> template<unsigned SamplesPerPixel>
template<Painter::WindingRule WindingRule> template<WindingRule WindingRule>
FLATTEN __attribute__((hot)) void EdgeFlagPathRasterizer<SamplesPerPixel>::write_scanline(Painter& painter, int scanline, EdgeExtent edge_extent, auto& color_or_function) FLATTEN __attribute__((hot)) void EdgeFlagPathRasterizer<SamplesPerPixel>::write_scanline(Painter& painter, int scanline, EdgeExtent edge_extent, auto& color_or_function)
{ {
// Handle scanline clipping. // Handle scanline clipping.
@ -383,7 +383,7 @@ FLATTEN __attribute__((hot)) void EdgeFlagPathRasterizer<SamplesPerPixel>::write
if (clipped_extent.min_x > clipped_extent.max_x) { if (clipped_extent.min_x > clipped_extent.max_x) {
// Fully clipped. Unfortunately we still need to zero the scanline data. // Fully clipped. Unfortunately we still need to zero the scanline data.
edge_extent.memset_extent(m_scanline.data(), 0); edge_extent.memset_extent(m_scanline.data(), 0);
if constexpr (WindingRule == Painter::WindingRule::Nonzero) if constexpr (WindingRule == WindingRule::Nonzero)
edge_extent.memset_extent(m_windings.data(), 0); edge_extent.memset_extent(m_windings.data(), 0);
return; return;
} }
@ -445,19 +445,19 @@ void Painter::fill_path(Path const& path, Color color, WindingRule winding_rule)
rasterizer.fill(*this, path, color, winding_rule); rasterizer.fill(*this, path, color, winding_rule);
} }
void Painter::fill_path(Path const& path, PaintStyle const& paint_style, float opacity, Painter::WindingRule winding_rule) void Painter::fill_path(Path const& path, PaintStyle const& paint_style, float opacity, WindingRule winding_rule)
{ {
EdgeFlagPathRasterizer<8> rasterizer(path_bounds(path)); EdgeFlagPathRasterizer<8> rasterizer(path_bounds(path));
rasterizer.fill(*this, path, paint_style, opacity, winding_rule); rasterizer.fill(*this, path, paint_style, opacity, winding_rule);
} }
void AntiAliasingPainter::fill_path(Path const& path, Color color, Painter::WindingRule winding_rule) void AntiAliasingPainter::fill_path(Path const& path, Color color, WindingRule winding_rule)
{ {
EdgeFlagPathRasterizer<32> rasterizer(path_bounds(path)); EdgeFlagPathRasterizer<32> rasterizer(path_bounds(path));
rasterizer.fill(m_underlying_painter, path, color, winding_rule, m_transform.translation()); rasterizer.fill(m_underlying_painter, path, color, winding_rule, m_transform.translation());
} }
void AntiAliasingPainter::fill_path(Path const& path, PaintStyle const& paint_style, float opacity, Painter::WindingRule winding_rule) void AntiAliasingPainter::fill_path(Path const& path, PaintStyle const& paint_style, float opacity, WindingRule winding_rule)
{ {
EdgeFlagPathRasterizer<32> rasterizer(path_bounds(path)); EdgeFlagPathRasterizer<32> rasterizer(path_bounds(path));
rasterizer.fill(m_underlying_painter, path, paint_style, opacity, winding_rule, m_transform.translation()); rasterizer.fill(m_underlying_painter, path, paint_style, opacity, winding_rule, m_transform.translation());

View file

@ -145,8 +145,8 @@ class EdgeFlagPathRasterizer {
public: public:
EdgeFlagPathRasterizer(IntSize); EdgeFlagPathRasterizer(IntSize);
void fill(Painter&, Path const&, Color, Painter::WindingRule, FloatPoint offset = {}); void fill(Painter&, Path const&, Color, WindingRule, FloatPoint offset = {});
void fill(Painter&, Path const&, PaintStyle const&, float opacity, Painter::WindingRule, FloatPoint offset = {}); void fill(Painter&, Path const&, PaintStyle const&, float opacity, WindingRule, FloatPoint offset = {});
private: private:
using SubpixelSample = Detail::Sample<SamplesPerPixel>; using SubpixelSample = Detail::Sample<SamplesPerPixel>;
@ -172,16 +172,16 @@ private:
} }
}; };
void fill_internal(Painter&, Path const&, auto color_or_function, Painter::WindingRule, FloatPoint offset); void fill_internal(Painter&, Path const&, auto color_or_function, WindingRule, FloatPoint offset);
Detail::Edge* plot_edges_for_scanline(int scanline, auto plot_edge, EdgeExtent&, Detail::Edge* active_edges = nullptr); Detail::Edge* plot_edges_for_scanline(int scanline, auto plot_edge, EdgeExtent&, Detail::Edge* active_edges = nullptr);
template<Painter::WindingRule> template<WindingRule>
FLATTEN void write_scanline(Painter&, int scanline, EdgeExtent, auto& color_or_function); FLATTEN void write_scanline(Painter&, int scanline, EdgeExtent, auto& color_or_function);
Color scanline_color(int scanline, int offset, u8 alpha, auto& color_or_function); Color scanline_color(int scanline, int offset, u8 alpha, auto& color_or_function);
void write_pixel(BitmapFormat format, ARGB32* scanline_ptr, int scanline, int offset, SampleType sample, auto& color_or_function); void write_pixel(BitmapFormat format, ARGB32* scanline_ptr, int scanline, int offset, SampleType sample, auto& color_or_function);
void fast_fill_solid_color_span(ARGB32* scanline_ptr, int start, int end, Color color); void fast_fill_solid_color_span(ARGB32* scanline_ptr, int start, int end, Color color);
template<Painter::WindingRule, typename Callback> template<WindingRule, typename Callback>
auto accumulate_scanline(EdgeExtent, auto, Callback); auto accumulate_scanline(EdgeExtent, auto, Callback);
auto accumulate_even_odd_scanline(EdgeExtent, auto, auto sample_callback); auto accumulate_even_odd_scanline(EdgeExtent, auto, auto sample_callback);
auto accumulate_non_zero_scanline(EdgeExtent, auto, auto sample_callback); auto accumulate_non_zero_scanline(EdgeExtent, auto, auto sample_callback);
@ -196,10 +196,10 @@ private:
WindingCounts winding; WindingCounts winding;
}; };
template<Painter::WindingRule WindingRule> template<WindingRule WindingRule>
constexpr auto initial_acc() const constexpr auto initial_acc() const
{ {
if constexpr (WindingRule == Painter::WindingRule::EvenOdd) if constexpr (WindingRule == WindingRule::EvenOdd)
return SampleType {}; return SampleType {};
else else
return NonZeroAcc {}; return NonZeroAcc {};

View file

@ -483,10 +483,10 @@ void TinyVGDecodedImageData::draw_transformed(Painter& painter, AffineTransform
auto fill_path = draw_path; auto fill_path = draw_path;
fill_path.close_all_subpaths(); fill_path.close_all_subpaths();
command.fill->visit( command.fill->visit(
[&](Color color) { aa_painter.fill_path(fill_path, color, Painter::WindingRule::EvenOdd); }, [&](Color color) { aa_painter.fill_path(fill_path, color, WindingRule::EvenOdd); },
[&](NonnullRefPtr<SVGGradientPaintStyle> style) { [&](NonnullRefPtr<SVGGradientPaintStyle> style) {
const_cast<SVGGradientPaintStyle&>(*style).set_gradient_transform(transform); const_cast<SVGGradientPaintStyle&>(*style).set_gradient_transform(transform);
aa_painter.fill_path(fill_path, style, 1.0f, Painter::WindingRule::EvenOdd); aa_painter.fill_path(fill_path, style, 1.0f, WindingRule::EvenOdd);
}); });
} }
if (command.stroke.has_value()) { if (command.stroke.has_value()) {

View file

@ -25,6 +25,7 @@
#include <LibGfx/TextDirection.h> #include <LibGfx/TextDirection.h>
#include <LibGfx/TextElision.h> #include <LibGfx/TextElision.h>
#include <LibGfx/TextWrapping.h> #include <LibGfx/TextWrapping.h>
#include <LibGfx/WindingRule.h>
namespace Gfx { namespace Gfx {
@ -104,11 +105,6 @@ public:
void stroke_path(Path const&, Color, int thickness); void stroke_path(Path const&, Color, int thickness);
enum class WindingRule {
Nonzero,
EvenOdd,
};
void fill_path(Path const&, Color, WindingRule rule = WindingRule::Nonzero); void fill_path(Path const&, Color, WindingRule rule = WindingRule::Nonzero);
void fill_path(Path const&, PaintStyle const& paint_style, float opacity = 1.0f, WindingRule rule = WindingRule::Nonzero); void fill_path(Path const&, PaintStyle const& paint_style, float opacity = 1.0f, WindingRule rule = WindingRule::Nonzero);

View file

@ -13,7 +13,7 @@ namespace Gfx {
struct ClipPath { struct ClipPath {
Path path; Path path;
Painter::WindingRule winding_rule; WindingRule winding_rule;
}; };
class PathClipper { class PathClipper {

View file

@ -0,0 +1,16 @@
/*
* Copyright (c) 2024, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
namespace Gfx {
enum class WindingRule {
Nonzero,
EvenOdd,
};
}

View file

@ -92,7 +92,7 @@ Gfx::Path CanvasRenderingContext2D::rect_path(float x, float y, float width, flo
void CanvasRenderingContext2D::fill_rect(float x, float y, float width, float height) void CanvasRenderingContext2D::fill_rect(float x, float y, float width, float height)
{ {
return fill_internal(rect_path(x, y, width, height), Gfx::Painter::WindingRule::EvenOdd); return fill_internal(rect_path(x, y, width, height), Gfx::WindingRule::EvenOdd);
} }
void CanvasRenderingContext2D::clear_rect(float x, float y, float width, float height) void CanvasRenderingContext2D::clear_rect(float x, float y, float width, float height)
@ -255,7 +255,7 @@ Gfx::Path CanvasRenderingContext2D::text_path(StringView text, float x, float y,
void CanvasRenderingContext2D::fill_text(StringView text, float x, float y, Optional<double> max_width) void CanvasRenderingContext2D::fill_text(StringView text, float x, float y, Optional<double> max_width)
{ {
fill_internal(text_path(text, x, y, max_width), Gfx::Painter::WindingRule::Nonzero); fill_internal(text_path(text, x, y, max_width), Gfx::WindingRule::Nonzero);
} }
void CanvasRenderingContext2D::stroke_text(StringView text, float x, float y, Optional<double> max_width) void CanvasRenderingContext2D::stroke_text(StringView text, float x, float y, Optional<double> max_width)
@ -292,17 +292,17 @@ void CanvasRenderingContext2D::stroke(Path2D const& path)
stroke_internal(transformed_path); stroke_internal(transformed_path);
} }
static Gfx::Painter::WindingRule parse_fill_rule(StringView fill_rule) static Gfx::WindingRule parse_fill_rule(StringView fill_rule)
{ {
if (fill_rule == "evenodd"sv) if (fill_rule == "evenodd"sv)
return Gfx::Painter::WindingRule::EvenOdd; return Gfx::WindingRule::EvenOdd;
if (fill_rule == "nonzero"sv) if (fill_rule == "nonzero"sv)
return Gfx::Painter::WindingRule::Nonzero; return Gfx::WindingRule::Nonzero;
dbgln("Unrecognized fillRule for CRC2D.fill() - this problem goes away once we pass an enum instead of a string"); dbgln("Unrecognized fillRule for CRC2D.fill() - this problem goes away once we pass an enum instead of a string");
return Gfx::Painter::WindingRule::Nonzero; return Gfx::WindingRule::Nonzero;
} }
void CanvasRenderingContext2D::fill_internal(Gfx::Path const& path, Gfx::Painter::WindingRule winding_rule) void CanvasRenderingContext2D::fill_internal(Gfx::Path const& path, Gfx::WindingRule winding_rule)
{ {
draw_clipped([&, this](auto& painter) mutable { draw_clipped([&, this](auto& painter) mutable {
auto path_to_fill = path; auto path_to_fill = path;
@ -537,7 +537,7 @@ CanvasRenderingContext2D::PreparedText CanvasRenderingContext2D::prepare_text(By
return prepared_text; return prepared_text;
} }
void CanvasRenderingContext2D::clip_internal(Gfx::Path& path, Gfx::Painter::WindingRule winding_rule) void CanvasRenderingContext2D::clip_internal(Gfx::Path& path, Gfx::WindingRule winding_rule)
{ {
// FIXME: This should calculate the new clip path by intersecting the given path with the current one. // FIXME: This should calculate the new clip path by intersecting the given path with the current one.
// See: https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-clip-dev // See: https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-clip-dev

View file

@ -144,8 +144,8 @@ private:
Gfx::Path text_path(StringView text, float x, float y, Optional<double> max_width); Gfx::Path text_path(StringView text, float x, float y, Optional<double> max_width);
void stroke_internal(Gfx::Path const&); void stroke_internal(Gfx::Path const&);
void fill_internal(Gfx::Path const&, Gfx::Painter::WindingRule); void fill_internal(Gfx::Path const&, Gfx::WindingRule);
void clip_internal(Gfx::Path&, Gfx::Painter::WindingRule); void clip_internal(Gfx::Path&, Gfx::WindingRule);
JS::NonnullGCPtr<HTMLCanvasElement> m_element; JS::NonnullGCPtr<HTMLCanvasElement> m_element;
OwnPtr<Gfx::Painter> m_painter; OwnPtr<Gfx::Painter> m_painter;

View file

@ -48,7 +48,7 @@ CommandResult AffineCommandExecutorCPU::fill_rect(FillRect const& command)
{ {
// FIXME: Somehow support clip_paths? // FIXME: Somehow support clip_paths?
auto path = rect_path(command.rect.to_type<float>()).copy_transformed(stacking_context().transform); auto path = rect_path(command.rect.to_type<float>()).copy_transformed(stacking_context().transform);
aa_painter().fill_path(path, command.color, Gfx::Painter::WindingRule::EvenOdd); aa_painter().fill_path(path, command.color, Gfx::WindingRule::EvenOdd);
return CommandResult::Continue; return CommandResult::Continue;
} }
@ -175,7 +175,7 @@ CommandResult AffineCommandExecutorCPU::fill_rect_with_rounded_corners(FillRectW
} }
path = path.copy_transformed(stacking_context().transform); path = path.copy_transformed(stacking_context().transform);
aa_painter().fill_path(path, command.color, Gfx::Painter::WindingRule::EvenOdd); aa_painter().fill_path(path, command.color, Gfx::WindingRule::EvenOdd);
return CommandResult::Continue; return CommandResult::Continue;
} }

View file

@ -191,7 +191,7 @@ void paint_border(RecordingPainter& painter, BorderEdge edge, DevicePixelRect co
path.close_all_subpaths(); path.close_all_subpaths();
painter.fill_path({ .path = path, painter.fill_path({ .path = path,
.color = color, .color = color,
.winding_rule = Gfx::Painter::WindingRule::EvenOdd }); .winding_rule = Gfx::WindingRule::EvenOdd });
path.clear(); path.clear();
} }
}; };

View file

@ -183,7 +183,7 @@ struct FillPathUsingColor {
Gfx::IntRect path_bounding_rect; Gfx::IntRect path_bounding_rect;
Gfx::Path path; Gfx::Path path;
Color color; Color color;
Gfx::Painter::WindingRule winding_rule; Gfx::WindingRule winding_rule;
Gfx::FloatPoint aa_translation; Gfx::FloatPoint aa_translation;
[[nodiscard]] Gfx::IntRect bounding_rect() const { return path_bounding_rect; } [[nodiscard]] Gfx::IntRect bounding_rect() const { return path_bounding_rect; }
@ -199,7 +199,7 @@ struct FillPathUsingPaintStyle {
Gfx::IntRect path_bounding_rect; Gfx::IntRect path_bounding_rect;
Gfx::Path path; Gfx::Path path;
NonnullRefPtr<Gfx::PaintStyle> paint_style; NonnullRefPtr<Gfx::PaintStyle> paint_style;
Gfx::Painter::WindingRule winding_rule; Gfx::WindingRule winding_rule;
float opacity; float opacity;
Gfx::FloatPoint aa_translation; Gfx::FloatPoint aa_translation;

View file

@ -88,7 +88,7 @@ void MarkerPaintable::paint(PaintContext& context, PaintPhase phase) const
path.line_to({ left + sin_60_deg * (right - left), (top + bottom) / 2 }); path.line_to({ left + sin_60_deg * (right - left), (top + bottom) / 2 });
path.line_to({ left, bottom }); path.line_to({ left, bottom });
path.close(); path.close();
context.recording_painter().fill_path({ .path = path, .color = color, .winding_rule = Gfx::Painter::WindingRule::EvenOdd }); context.recording_painter().fill_path({ .path = path, .color = color, .winding_rule = Gfx::WindingRule::EvenOdd });
break; break;
} }
case CSS::ListStyleType::DisclosureOpen: { case CSS::ListStyleType::DisclosureOpen: {
@ -102,7 +102,7 @@ void MarkerPaintable::paint(PaintContext& context, PaintPhase phase) const
path.line_to({ right, top }); path.line_to({ right, top });
path.line_to({ (left + right) / 2, top + sin_60_deg * (bottom - top) }); path.line_to({ (left + right) / 2, top + sin_60_deg * (bottom - top) });
path.close(); path.close();
context.recording_painter().fill_path({ .path = path, .color = color, .winding_rule = Gfx::Painter::WindingRule::EvenOdd }); context.recording_painter().fill_path({ .path = path, .color = color, .winding_rule = Gfx::WindingRule::EvenOdd });
break; break;
} }
case CSS::ListStyleType::Decimal: case CSS::ListStyleType::Decimal:

View file

@ -54,7 +54,7 @@ void MediaPaintable::fill_triangle(RecordingPainter& painter, Gfx::IntPoint loca
painter.fill_path({ painter.fill_path({
.path = path, .path = path,
.color = color, .color = color,
.winding_rule = Gfx::Painter::WindingRule::EvenOdd, .winding_rule = Gfx::WindingRule::EvenOdd,
}); });
} }
@ -227,7 +227,7 @@ void MediaPaintable::paint_control_bar_speaker(PaintContext& context, HTML::HTML
path.line_to(device_point(0, 11)); path.line_to(device_point(0, 11));
path.line_to(device_point(0, 4)); path.line_to(device_point(0, 4));
path.close(); path.close();
context.recording_painter().fill_path({ .path = path, .color = speaker_button_color, .winding_rule = Gfx::Painter::WindingRule::EvenOdd }); context.recording_painter().fill_path({ .path = path, .color = speaker_button_color, .winding_rule = Gfx::WindingRule::EvenOdd });
path.clear(); path.clear();
path.move_to(device_point(13, 3)); path.move_to(device_point(13, 3));

View file

@ -49,7 +49,7 @@ public:
struct FillPathUsingColorParams { struct FillPathUsingColorParams {
Gfx::Path path; Gfx::Path path;
Gfx::Color color; Gfx::Color color;
Gfx::Painter::WindingRule winding_rule = Gfx::Painter::WindingRule::EvenOdd; Gfx::WindingRule winding_rule = Gfx::WindingRule::EvenOdd;
Optional<Gfx::FloatPoint> translation = {}; Optional<Gfx::FloatPoint> translation = {};
}; };
void fill_path(FillPathUsingColorParams params); void fill_path(FillPathUsingColorParams params);
@ -57,7 +57,7 @@ public:
struct FillPathUsingPaintStyleParams { struct FillPathUsingPaintStyleParams {
Gfx::Path path; Gfx::Path path;
NonnullRefPtr<Gfx::PaintStyle> paint_style; NonnullRefPtr<Gfx::PaintStyle> paint_style;
Gfx::Painter::WindingRule winding_rule = Gfx::Painter::WindingRule::EvenOdd; Gfx::WindingRule winding_rule = Gfx::WindingRule::EvenOdd;
float opacity; float opacity;
Optional<Gfx::FloatPoint> translation = {}; Optional<Gfx::FloatPoint> translation = {};
}; };

View file

@ -38,13 +38,13 @@ TraversalDecision SVGPathPaintable::hit_test(CSSPixelPoint position, HitTestType
return SVGGraphicsPaintable::hit_test(position, type, callback); return SVGGraphicsPaintable::hit_test(position, type, callback);
} }
static Gfx::Painter::WindingRule to_gfx_winding_rule(SVG::FillRule fill_rule) static Gfx::WindingRule to_gfx_winding_rule(SVG::FillRule fill_rule)
{ {
switch (fill_rule) { switch (fill_rule) {
case SVG::FillRule::Nonzero: case SVG::FillRule::Nonzero:
return Gfx::Painter::WindingRule::Nonzero; return Gfx::WindingRule::Nonzero;
case SVG::FillRule::Evenodd: case SVG::FillRule::Evenodd:
return Gfx::Painter::WindingRule::EvenOdd; return Gfx::WindingRule::EvenOdd;
default: default:
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }