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)