diff --git a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasPath.cpp b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasPath.cpp
index 2577583f68..1b42fb3bbc 100644
--- a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasPath.cpp
+++ b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasPath.cpp
@@ -10,6 +10,13 @@
namespace Web::HTML {
+Gfx::AffineTransform CanvasPath::active_transform() const
+{
+ if (m_canvas_state.has_value())
+ return m_canvas_state->drawing_state().transform;
+ return {};
+}
+
void CanvasPath::close_path()
{
m_path.close();
@@ -17,22 +24,25 @@ void CanvasPath::close_path()
void CanvasPath::move_to(float x, float y)
{
- m_path.move_to({ x, y });
+ m_path.move_to(active_transform().map(Gfx::FloatPoint { x, y }));
}
void CanvasPath::line_to(float x, float y)
{
- m_path.line_to({ x, y });
+ m_path.line_to(active_transform().map(Gfx::FloatPoint { x, y }));
}
void CanvasPath::quadratic_curve_to(float cx, float cy, float x, float y)
{
- m_path.quadratic_bezier_curve_to({ cx, cy }, { x, y });
+ auto transform = active_transform();
+ m_path.quadratic_bezier_curve_to(transform.map(Gfx::FloatPoint { cx, cy }), transform.map(Gfx::FloatPoint { x, y }));
}
void CanvasPath::bezier_curve_to(double cp1x, double cp1y, double cp2x, double cp2y, double x, double y)
{
- m_path.cubic_bezier_curve_to(Gfx::FloatPoint(cp1x, cp1y), Gfx::FloatPoint(cp2x, cp2y), Gfx::FloatPoint(x, y));
+ auto transform = active_transform();
+ m_path.cubic_bezier_curve_to(
+ transform.map(Gfx::FloatPoint { cp1x, cp1y }), transform.map(Gfx::FloatPoint { cp2x, cp2y }), transform.map(Gfx::FloatPoint { x, y }));
}
WebIDL::ExceptionOr CanvasPath::arc(float x, float y, float radius, float start_angle, float end_angle, bool counter_clockwise)
@@ -97,23 +107,28 @@ WebIDL::ExceptionOr CanvasPath::ellipse(float x, float y, float radius_x,
auto start_point = resolve_point_with_angle(start_angle);
auto end_point = resolve_point_with_angle(end_angle);
- m_path.move_to(start_point);
-
auto delta_theta = end_angle - start_angle;
- m_path.elliptical_arc_to(end_point, { radius_x, radius_y }, rotation, delta_theta > AK::Pi, !counter_clockwise);
+ auto transform = active_transform();
+ m_path.move_to(transform.map(start_point));
+ m_path.elliptical_arc_to(
+ transform.map(Gfx::FloatPoint { end_point }),
+ transform.map(Gfx::FloatSize { radius_x, radius_y }),
+ rotation + transform.rotation(),
+ delta_theta > AK::Pi, !counter_clockwise);
return {};
}
void CanvasPath::rect(float x, float y, float width, float height)
{
- m_path.move_to({ x, y });
+ auto transform = active_transform();
+ m_path.move_to(transform.map(Gfx::FloatPoint { x, y }));
if (width == 0 || height == 0)
return;
- m_path.line_to({ x + width, y });
- m_path.line_to({ x + width, y + height });
- m_path.line_to({ x, y + height });
+ m_path.line_to(transform.map(Gfx::FloatPoint { x + width, y }));
+ m_path.line_to(transform.map(Gfx::FloatPoint { x + width, y + height }));
+ m_path.line_to(transform.map(Gfx::FloatPoint { x, y + height }));
m_path.close();
}
diff --git a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasPath.h b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasPath.h
index c9c584d5a7..6510239c15 100644
--- a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasPath.h
+++ b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasPath.h
@@ -7,6 +7,7 @@
#pragma once
#include
+#include
#include
namespace Web::HTML {
@@ -35,8 +36,17 @@ protected:
{
}
+ explicit CanvasPath(Bindings::PlatformObject& self, CanvasState const& canvas_state)
+ : m_self(self)
+ , m_canvas_state(canvas_state)
+ {
+ }
+
private:
+ Gfx::AffineTransform active_transform() const;
+
JS::NonnullGCPtr m_self;
+ Optional m_canvas_state;
Gfx::Path m_path;
};
diff --git a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp
index 85515d76c6..e614126c2d 100644
--- a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp
+++ b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp
@@ -33,7 +33,7 @@ WebIDL::ExceptionOr> CanvasRenderingC
CanvasRenderingContext2D::CanvasRenderingContext2D(JS::Realm& realm, HTMLCanvasElement& element)
: PlatformObject(realm)
- , CanvasPath(static_cast(*this))
+ , CanvasPath(static_cast(*this), *this)
, m_element(element)
{
}
@@ -243,8 +243,7 @@ void CanvasRenderingContext2D::stroke_internal(Gfx::Path const& path)
void CanvasRenderingContext2D::stroke()
{
- auto transformed_path = path().copy_transformed(drawing_state().transform);
- stroke_internal(transformed_path);
+ stroke_internal(path());
}
void CanvasRenderingContext2D::stroke(Path2D const& path)
@@ -265,7 +264,7 @@ static Gfx::Painter::WindingRule parse_fill_rule(StringView fill_rule)
void CanvasRenderingContext2D::fill_internal(Gfx::Path& path, StringView fill_rule_value)
{
- draw_clipped([&](auto& painter) {
+ draw_clipped([=, this](auto& painter) mutable {
path.close_all_subpaths();
auto& drawing_state = this->drawing_state();
auto fill_rule = parse_fill_rule(fill_rule_value);
@@ -280,8 +279,7 @@ void CanvasRenderingContext2D::fill_internal(Gfx::Path& path, StringView fill_ru
void CanvasRenderingContext2D::fill(DeprecatedString const& fill_rule)
{
- auto transformed_path = path().copy_transformed(drawing_state().transform);
- return fill_internal(transformed_path, fill_rule);
+ return fill_internal(path(), fill_rule);
}
void CanvasRenderingContext2D::fill(Path2D& path, DeprecatedString const& fill_rule)