Coverage Report

Created: 2026-02-16 07:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.h
Line
Count
Source
1
/*
2
 * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
3
 * Copyright (c) 2023, Bastiaan van der Plaat <bastiaan.v.d.plaat@gmail.com>
4
 * Copyright (c) 2024, Kenneth Myhra <kennethmyhra@serenityos.org>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
7
 */
8
9
#pragma once
10
11
#include <LibGfx/Matrix4x4.h>
12
#include <LibWeb/Bindings/PlatformObject.h>
13
#include <LibWeb/Bindings/Serializable.h>
14
#include <LibWeb/Forward.h>
15
#include <LibWeb/WebIDL/Buffers.h>
16
17
namespace Web::Geometry {
18
19
// https://drafts.fxtf.org/geometry/#dictdef-dommatrix2dinit
20
struct DOMMatrix2DInit {
21
    Optional<double> a;
22
    Optional<double> b;
23
    Optional<double> c;
24
    Optional<double> d;
25
    Optional<double> e;
26
    Optional<double> f;
27
    Optional<double> m11;
28
    Optional<double> m12;
29
    Optional<double> m21;
30
    Optional<double> m22;
31
    Optional<double> m41;
32
    Optional<double> m42;
33
};
34
35
// https://drafts.fxtf.org/geometry/#dictdef-dommatrixinit
36
struct DOMMatrixInit : public DOMMatrix2DInit {
37
    double m13 { 0.0 };
38
    double m14 { 0.0 };
39
    double m23 { 0.0 };
40
    double m24 { 0.0 };
41
    double m31 { 0.0 };
42
    double m32 { 0.0 };
43
    double m33 { 0.0 };
44
    double m34 { 0.0 };
45
    double m43 { 0.0 };
46
    double m44 { 0.0 };
47
    Optional<bool> is2d;
48
};
49
50
// https://drafts.fxtf.org/geometry/#dommatrixreadonly
51
class DOMMatrixReadOnly
52
    : public Bindings::PlatformObject
53
    , public Bindings::Serializable {
54
    WEB_PLATFORM_OBJECT(DOMMatrixReadOnly, Bindings::PlatformObject);
55
    JS_DECLARE_ALLOCATOR(DOMMatrixReadOnly);
56
57
public:
58
    static WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrixReadOnly>> construct_impl(JS::Realm&, Optional<Variant<String, Vector<double>>> const& init);
59
    static WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrixReadOnly>> create_from_dom_matrix_2d_init(JS::Realm&, DOMMatrix2DInit& init);
60
    static WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrixReadOnly>> create_from_dom_matrix_init(JS::Realm&, DOMMatrixInit& init);
61
    static JS::NonnullGCPtr<DOMMatrixReadOnly> create(JS::Realm&);
62
63
    virtual ~DOMMatrixReadOnly() override;
64
65
    static WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrixReadOnly>> from_matrix(JS::VM&, DOMMatrixInit& other);
66
    static WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrixReadOnly>> from_float32_array(JS::VM&, JS::Handle<WebIDL::BufferSource> const& array32);
67
    static WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrixReadOnly>> from_float64_array(JS::VM&, JS::Handle<WebIDL::BufferSource> const& array64);
68
69
    // https://drafts.fxtf.org/geometry/#dommatrix-attributes
70
0
    double m11() const { return m_matrix.elements()[0][0]; }
71
0
    double m12() const { return m_matrix.elements()[1][0]; }
72
0
    double m13() const { return m_matrix.elements()[2][0]; }
73
0
    double m14() const { return m_matrix.elements()[3][0]; }
74
0
    double m21() const { return m_matrix.elements()[0][1]; }
75
0
    double m22() const { return m_matrix.elements()[1][1]; }
76
0
    double m23() const { return m_matrix.elements()[2][1]; }
77
0
    double m24() const { return m_matrix.elements()[3][1]; }
78
0
    double m31() const { return m_matrix.elements()[0][2]; }
79
0
    double m32() const { return m_matrix.elements()[1][2]; }
80
0
    double m33() const { return m_matrix.elements()[2][2]; }
81
0
    double m34() const { return m_matrix.elements()[3][2]; }
82
0
    double m41() const { return m_matrix.elements()[0][3]; }
83
0
    double m42() const { return m_matrix.elements()[1][3]; }
84
0
    double m43() const { return m_matrix.elements()[2][3]; }
85
0
    double m44() const { return m_matrix.elements()[3][3]; }
86
87
0
    double a() const { return m11(); }
88
0
    double b() const { return m12(); }
89
0
    double c() const { return m21(); }
90
0
    double d() const { return m22(); }
91
0
    double e() const { return m41(); }
92
0
    double f() const { return m42(); }
93
94
0
    bool is2d() const { return m_is_2d; }
95
    bool is_identity() const;
96
97
    JS::NonnullGCPtr<DOMMatrix> translate(Optional<double> const& tx, Optional<double> const& ty, Optional<double> const& tz) const;
98
    JS::NonnullGCPtr<DOMMatrix> scale(Optional<double> scale_x, Optional<double> scale_y, Optional<double> scale_z, Optional<double> origin_x, Optional<double> origin_y, Optional<double> origin_z);
99
    JS::NonnullGCPtr<DOMMatrix> scale_non_uniform(Optional<double> scale_x, Optional<double> scale_y);
100
    JS::NonnullGCPtr<DOMMatrix> scale3d(Optional<double> scale, Optional<double> origin_x, Optional<double> origin_y, Optional<double> origin_z);
101
    JS::NonnullGCPtr<DOMMatrix> rotate(Optional<double> rot_x, Optional<double> rot_y, Optional<double> rot_z);
102
    JS::NonnullGCPtr<DOMMatrix> rotate_from_vector(Optional<double> x, Optional<double> y);
103
    JS::NonnullGCPtr<DOMMatrix> rotate_axis_angle(Optional<double> x, Optional<double> y, Optional<double> z, Optional<double> angle);
104
    JS::NonnullGCPtr<DOMMatrix> skew_x(double sx = 0) const;
105
    JS::NonnullGCPtr<DOMMatrix> skew_y(double sy = 0) const;
106
    WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrix>> multiply(DOMMatrixInit other = {});
107
    JS::NonnullGCPtr<DOMMatrix> flip_x();
108
    JS::NonnullGCPtr<DOMMatrix> flip_y();
109
    JS::NonnullGCPtr<DOMMatrix> inverse() const;
110
111
    JS::NonnullGCPtr<DOMPoint> transform_point(DOMPointInit const&) const;
112
    JS::NonnullGCPtr<DOMPoint> transform_point(DOMPointReadOnly const&) const;
113
    JS::NonnullGCPtr<JS::Float32Array> to_float32_array() const;
114
    JS::NonnullGCPtr<JS::Float64Array> to_float64_array() const;
115
116
    WebIDL::ExceptionOr<String> to_string() const;
117
118
0
    virtual StringView interface_name() const override { return "DOMMatrixReadOnly"sv; }
119
    virtual WebIDL::ExceptionOr<void> serialization_steps(HTML::SerializationRecord&, bool for_storage, HTML::SerializationMemory&) override;
120
    virtual WebIDL::ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const& record, size_t& position, HTML::DeserializationMemory&) override;
121
122
protected:
123
    DOMMatrixReadOnly(JS::Realm&, double m11, double m12, double m21, double m22, double m41, double m42);
124
    DOMMatrixReadOnly(JS::Realm&, double m11, double m12, double m13, double m14, double m21, double m22, double m23, double m24, double m31, double m32, double m33, double m34, double m41, double m42, double m43, double m44);
125
    DOMMatrixReadOnly(JS::Realm&, DOMMatrixReadOnly const& other);
126
    explicit DOMMatrixReadOnly(JS::Realm&);
127
128
    virtual void initialize(JS::Realm&) override;
129
130
    // NOTE: The matrix used in the spec is column-major (https://drafts.fxtf.org/geometry/#4x4-abstract-matrix) but Gfx::Matrix4x4 is row-major so we need to transpose the values.
131
    Gfx::DoubleMatrix4x4 m_matrix { Gfx::DoubleMatrix4x4::identity() };
132
133
    bool m_is_2d { true };
134
135
private:
136
    void initialize_from_create_2d_matrix(double m11, double m12, double m21, double m22, double m41, double m42);
137
    void initialize_from_create_3d_matrix(double m11, double m12, double m13, double m14, double m21, double m22, double m23, double m24, double m31, double m32, double m33, double m34, double m41, double m42, double m43, double m44);
138
};
139
140
WebIDL::ExceptionOr<void> validate_and_fixup_dom_matrix_2d_init(DOMMatrix2DInit& init);
141
WebIDL::ExceptionOr<void> validate_and_fixup_dom_matrix_init(DOMMatrixInit& init);
142
143
struct ParsedMatrix {
144
    Gfx::DoubleMatrix4x4 matrix;
145
    bool is_2d_transform;
146
};
147
148
WebIDL::ExceptionOr<ParsedMatrix> parse_dom_matrix_init_string(JS::Realm& realm, StringView transform_list);
149
150
}