1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 17:07:34 +00:00

LibWeb: Extract CanvasTransform class from CRC2D

The implementation of this got a little funky, because it has to access
methods from CanvasState.
This commit is contained in:
Sam Atkins 2022-08-12 14:48:11 +01:00 committed by Andreas Kling
parent 08e6071ebb
commit aa87b9699e
5 changed files with 101 additions and 69 deletions

View file

@ -0,0 +1,84 @@
/*
* Copyright (c) 2020-2022, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Debug.h>
#include <LibWeb/HTML/Canvas/CanvasState.h>
namespace Web::HTML {
// https://html.spec.whatwg.org/multipage/canvas.html#canvastransform
template<typename IncludingClass>
class CanvasTransform {
public:
~CanvasTransform() = default;
void scale(float sx, float sy)
{
dbgln_if(CANVAS_RENDERING_CONTEXT_2D_DEBUG, "CanvasTransform::scale({}, {})", sx, sy);
my_drawing_state().transform.scale(sx, sy);
}
void translate(float tx, float ty)
{
dbgln_if(CANVAS_RENDERING_CONTEXT_2D_DEBUG, "CanvasTransform::translate({}, {})", tx, ty);
my_drawing_state().transform.translate(tx, ty);
}
void rotate(float radians)
{
dbgln_if(CANVAS_RENDERING_CONTEXT_2D_DEBUG, "CanvasTransform::rotate({})", radians);
my_drawing_state().transform.rotate_radians(radians);
}
// https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-transform
void transform(double a, double b, double c, double d, double e, double f)
{
// 1. If any of the arguments are infinite or NaN, then return.
if (!isfinite(a) || !isfinite(b) || !isfinite(c) || !isfinite(d) || !isfinite(e) || !isfinite(f))
return;
// 2. Replace the current transformation matrix with the result of multiplying the current transformation matrix with the matrix described by:
// a c e
// b d f
// 0 0 1
my_drawing_state().transform.multiply({ static_cast<float>(a), static_cast<float>(b), static_cast<float>(c), static_cast<float>(d), static_cast<float>(e), static_cast<float>(f) });
}
// https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-settransform
void set_transform(double a, double b, double c, double d, double e, double f)
{
// 1. If any of the arguments are infinite or NaN, then return.
if (!isfinite(a) || !isfinite(b) || !isfinite(c) || !isfinite(d) || !isfinite(e) || !isfinite(f))
return;
// 2. Reset the current transformation matrix to the identity matrix.
my_drawing_state().transform = {};
// 3. Invoke the transform(a, b, c, d, e, f) method with the same arguments.
transform(a, b, c, d, e, f);
}
// https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-resettransform
void reset_transform()
{
// The resetTransform() method, when invoked, must reset the current transformation matrix to the identity matrix.
my_drawing_state().transform = {};
}
protected:
CanvasTransform() = default;
private:
CanvasState::DrawingState& my_drawing_state() { return reinterpret_cast<IncludingClass&>(*this).drawing_state(); }
CanvasState::DrawingState const& my_drawing_state() const { return reinterpret_cast<IncludingClass const&>(*this).drawing_state(); }
};
}

View file

@ -0,0 +1,12 @@
// https://html.spec.whatwg.org/multipage/canvas.html#canvastransform
interface mixin CanvasTransform {
undefined scale(unrestricted double x, unrestricted double y);
undefined rotate(unrestricted double radians);
undefined translate(unrestricted double x, unrestricted double y);
undefined transform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f);
// FIXME: [NewObject] DOMMatrix getTransform();
undefined setTransform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f);
// FIXME: undefined setTransform(optional DOMMatrix2DInit transform = {});
undefined resetTransform();
};

View file

@ -263,24 +263,6 @@ DOM::ExceptionOr<void> CanvasRenderingContext2D::draw_image(CanvasImageSource co
return {};
}
void CanvasRenderingContext2D::scale(float sx, float sy)
{
dbgln_if(CANVAS_RENDERING_CONTEXT_2D_DEBUG, "CanvasRenderingContext2D::scale({}, {})", sx, sy);
drawing_state().transform.scale(sx, sy);
}
void CanvasRenderingContext2D::translate(float tx, float ty)
{
dbgln_if(CANVAS_RENDERING_CONTEXT_2D_DEBUG, "CanvasRenderingContext2D::translate({}, {})", tx, ty);
drawing_state().transform.translate(tx, ty);
}
void CanvasRenderingContext2D::rotate(float radians)
{
dbgln_if(CANVAS_RENDERING_CONTEXT_2D_DEBUG, "CanvasRenderingContext2D::rotate({})", radians);
drawing_state().transform.rotate_radians(radians);
}
void CanvasRenderingContext2D::did_draw(Gfx::FloatRect const&)
{
// FIXME: Make use of the rect to reduce the invalidated area when possible.
@ -601,41 +583,6 @@ NonnullRefPtr<CanvasGradient> CanvasRenderingContext2D::create_conic_gradient(do
return CanvasGradient::create_conic(start_angle, x, y);
}
// https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-transform
void CanvasRenderingContext2D::transform(double a, double b, double c, double d, double e, double f)
{
// 1. If any of the arguments are infinite or NaN, then return.
if (!isfinite(a) || !isfinite(b) || !isfinite(c) || !isfinite(d) || !isfinite(e) || !isfinite(f))
return;
// 2. Replace the current transformation matrix with the result of multiplying the current transformation matrix with the matrix described by:
// a c e
// b d f
// 0 0 1
drawing_state().transform.multiply({ static_cast<float>(a), static_cast<float>(b), static_cast<float>(c), static_cast<float>(d), static_cast<float>(e), static_cast<float>(f) });
}
// https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-settransform
void CanvasRenderingContext2D::set_transform(double a, double b, double c, double d, double e, double f)
{
// 1. If any of the arguments are infinite or NaN, then return.
if (!isfinite(a) || !isfinite(b) || !isfinite(c) || !isfinite(d) || !isfinite(e) || !isfinite(f))
return;
// 2. Reset the current transformation matrix to the identity matrix.
drawing_state().transform = {};
// 3. Invoke the transform(a, b, c, d, e, f) method with the same arguments.
transform(a, b, c, d, e, f);
}
// https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-resettransform
void CanvasRenderingContext2D::reset_transform()
{
// The resetTransform() method, when invoked, must reset the current transformation matrix to the identity matrix.
drawing_state().transform = {};
}
void CanvasRenderingContext2D::clip()
{
// FIXME: Implement.

View file

@ -18,6 +18,7 @@
#include <LibWeb/DOM/ExceptionOr.h>
#include <LibWeb/HTML/Canvas/CanvasPath.h>
#include <LibWeb/HTML/Canvas/CanvasState.h>
#include <LibWeb/HTML/Canvas/CanvasTransform.h>
#include <LibWeb/HTML/CanvasGradient.h>
#include <LibWeb/Layout/InlineNode.h>
#include <LibWeb/Layout/LineBox.h>
@ -32,7 +33,8 @@ class CanvasRenderingContext2D
: public RefCountForwarder<HTMLCanvasElement>
, public Bindings::Wrappable
, public CanvasPath
, public CanvasState {
, public CanvasState
, public CanvasTransform<CanvasRenderingContext2D> {
AK_MAKE_NONCOPYABLE(CanvasRenderingContext2D);
AK_MAKE_NONMOVABLE(CanvasRenderingContext2D);
@ -57,10 +59,6 @@ public:
DOM::ExceptionOr<void> draw_image(CanvasImageSource const&, float destination_x, float destination_y, float destination_width, float destination_height);
DOM::ExceptionOr<void> draw_image(CanvasImageSource const&, float source_x, float source_y, float source_width, float source_height, float destination_x, float destination_y, float destination_width, float destination_height);
void scale(float sx, float sy);
void translate(float x, float y);
void rotate(float degrees);
void set_line_width(float line_width) { drawing_state().line_width = line_width; }
float line_width() const { return drawing_state().line_width; }
@ -88,9 +86,6 @@ public:
NonnullRefPtr<CanvasGradient> create_linear_gradient(double x0, double y0, double x1, double y1);
NonnullRefPtr<CanvasGradient> create_conic_gradient(double start_angle, double x, double y);
void transform(double a, double b, double c, double d, double e, double f);
void set_transform(double a, double b, double c, double d, double e, double f);
void reset_transform();
void clip();
private:

View file

@ -5,6 +5,7 @@
#import <HTML/CanvasGradient.idl>
#import <HTML/Canvas/CanvasPath.idl>
#import <HTML/Canvas/CanvasState.idl>
#import <HTML/Canvas/CanvasTransform.idl>
#import <HTML/Path2D.idl>
// https://html.spec.whatwg.org/multipage/canvas.html#canvasrenderingcontext2d
@ -15,10 +16,6 @@ interface CanvasRenderingContext2D {
undefined strokeRect(double x, double y, double w, double h);
undefined clearRect(double x, double y, double w, double h);
undefined scale(double x, double y);
undefined translate(double x, double y);
undefined rotate(double radians);
undefined beginPath();
// FIXME: `DOMString` should be `CanvasFillRule`
undefined fill(optional DOMString fillRule = "nonzero");
@ -50,10 +47,6 @@ interface CanvasRenderingContext2D {
CanvasGradient createLinearGradient(double x0, double y0, double x1, double y1);
CanvasGradient createConicGradient(double startAngle, double x, double y);
undefined transform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f);
undefined setTransform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f);
undefined resetTransform();
// undefined clip(optional CanvasFillRule fillRule = "nonzero");
// undefined clip(Path2D path, optional CanvasFillRule fillRule = "nonzero");
// FIXME: Replace this with the two definitions above.
@ -62,4 +55,5 @@ interface CanvasRenderingContext2D {
};
CanvasRenderingContext2D includes CanvasState;
CanvasRenderingContext2D includes CanvasTransform;
CanvasRenderingContext2D includes CanvasPath;