Serenity Operating System
1/*
2 * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <LibWeb/Bindings/Intrinsics.h>
8#include <LibWeb/Geometry/DOMMatrix.h>
9#include <LibWeb/WebIDL/ExceptionOr.h>
10
11namespace Web::Geometry {
12
13WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrix>> DOMMatrix::construct_impl(JS::Realm& realm, Optional<Variant<String, Vector<double>>> const& init)
14{
15 auto& vm = realm.vm();
16
17 // https://drafts.fxtf.org/geometry/#dom-dommatrix-dommatrix
18 if (init.has_value()) {
19 // -> Otherwise
20 // Throw a TypeError exception.
21 // The only condition where this can be met is with a sequence type which doesn't have exactly 6 or 16 elements.
22 if (auto* double_sequence = init.value().get_pointer<Vector<double>>(); double_sequence && (double_sequence->size() != 6 && double_sequence->size() != 16))
23 return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, TRY_OR_THROW_OOM(vm, String::formatted("Sequence must contain exactly 6 or 16 elements, got {} element(s)", double_sequence->size())) };
24 }
25
26 return realm.heap().allocate<DOMMatrix>(realm, realm, init).release_allocated_value_but_fixme_should_propagate_errors();
27}
28
29// https://drafts.fxtf.org/geometry/#create-a-dommatrix-from-the-2d-dictionary
30WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrix>> DOMMatrix::create_from_dom_matrix_2d_init(JS::Realm& realm, DOMMatrix2DInit& init)
31{
32 // 1. Validate and fixup (2D) other.
33 TRY(validate_and_fixup_dom_matrix_2d_init(init));
34
35 // These should all have values after calling `validate_and_fixup_dom_matrix_2d_init`
36 VERIFY(init.m11.has_value());
37 VERIFY(init.m12.has_value());
38 VERIFY(init.m21.has_value());
39 VERIFY(init.m22.has_value());
40 VERIFY(init.m41.has_value());
41 VERIFY(init.m42.has_value());
42
43 // 2. Return the result of invoking create a 2d matrix of type DOMMatrixReadOnly or DOMMatrix as appropriate, with a sequence of numbers,
44 // the values being the 6 elements m11, m12, m21, m22, m41 and m42 of other in the given order.
45 return realm.heap().allocate<DOMMatrix>(realm, realm, init.m11.value(), init.m12.value(), init.m21.value(), init.m22.value(), init.m41.value(), init.m42.value()).release_allocated_value_but_fixme_should_propagate_errors();
46}
47
48JS::NonnullGCPtr<DOMMatrix> DOMMatrix::create_from_dom_matrix_read_only(JS::Realm& realm, DOMMatrixReadOnly const& read_only_matrix)
49{
50 return realm.heap().allocate<DOMMatrix>(realm, realm, read_only_matrix).release_allocated_value_but_fixme_should_propagate_errors();
51}
52
53DOMMatrix::DOMMatrix(JS::Realm& realm, double m11, double m12, double m21, double m22, double m41, double m42)
54 : DOMMatrixReadOnly(realm, m11, m12, m21, m22, m41, m42)
55{
56}
57
58DOMMatrix::DOMMatrix(JS::Realm& realm, Optional<Variant<String, Vector<double>>> const& init)
59 : DOMMatrixReadOnly(realm, init)
60{
61}
62
63DOMMatrix::DOMMatrix(JS::Realm& realm, DOMMatrixReadOnly const& read_only_matrix)
64 : DOMMatrixReadOnly(realm, read_only_matrix)
65{
66}
67
68DOMMatrix::~DOMMatrix() = default;
69
70JS::ThrowCompletionOr<void> DOMMatrix::initialize(JS::Realm& realm)
71{
72 MUST_OR_THROW_OOM(Base::initialize(realm));
73 set_prototype(&Bindings::ensure_web_prototype<Bindings::DOMMatrixPrototype>(realm, "DOMMatrix"));
74
75 return {};
76}
77
78// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m11
79void DOMMatrix::set_m11(double value)
80{
81 // For the DOMMatrix interface, setting the m11 or the a attribute must set the m11 element to the new value.
82 m_matrix.elements()[0][0] = value;
83}
84
85// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m12
86void DOMMatrix::set_m12(double value)
87{
88 // For the DOMMatrix interface, setting the m12 or the b attribute must set the m12 element to the new value.
89 m_matrix.elements()[0][1] = value;
90}
91
92// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m13
93void DOMMatrix::set_m13(double value)
94{
95 // For the DOMMatrix interface, setting the m13 attribute must set the m13 element to the new value and, if the new value is not 0 or -0, set is 2D to false.
96 m_matrix.elements()[0][2] = value;
97 if (value != 0.0 && value != -0.0)
98 m_is_2d = false;
99}
100
101// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m14
102void DOMMatrix::set_m14(double value)
103{
104 // For the DOMMatrix interface, setting the m14 attribute must set the m14 element to the new value and, if the new value is not 0 or -0, set is 2D to false.
105 m_matrix.elements()[0][3] = value;
106 if (value != 0.0 && value != -0.0)
107 m_is_2d = false;
108}
109
110// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m21
111void DOMMatrix::set_m21(double value)
112{
113 // For the DOMMatrix interface, setting the m21 or the c attribute must set the m21 element to the new value.
114 m_matrix.elements()[1][0] = value;
115}
116
117// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m22
118void DOMMatrix::set_m22(double value)
119{
120 // For the DOMMatrix interface, setting the m22 or the d attribute must set the m22 element to the new value.
121 m_matrix.elements()[1][1] = value;
122}
123
124// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m23
125void DOMMatrix::set_m23(double value)
126{
127 // For the DOMMatrix interface, setting the m23 attribute must set the m23 element to the new value and, if the new value is not 0 or -0, set is 2D to false.
128 m_matrix.elements()[1][2] = value;
129 if (value != 0.0 && value != -0.0)
130 m_is_2d = false;
131}
132
133// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m24
134void DOMMatrix::set_m24(double value)
135{
136 // For the DOMMatrix interface, setting the m24 attribute must set the m24 element to the new value and, if the new value is not 0 or -0, set is 2D to false.
137 m_matrix.elements()[1][3] = value;
138 if (value != 0.0 && value != -0.0)
139 m_is_2d = false;
140}
141
142// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m31
143void DOMMatrix::set_m31(double value)
144{
145 // For the DOMMatrix interface, setting the m31 attribute must set the m31 element to the new value and, if the new value is not 0 or -0, set is 2D to false.
146 m_matrix.elements()[2][0] = value;
147 if (value != 0.0 && value != -0.0)
148 m_is_2d = false;
149}
150
151// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m32
152void DOMMatrix::set_m32(double value)
153{
154 // For the DOMMatrix interface, setting the m32 attribute must set the m32 element to the new value and, if the new value is not 0 or -0, set is 2D to false.
155 m_matrix.elements()[2][1] = value;
156 if (value != 0.0 && value != -0.0)
157 m_is_2d = false;
158}
159
160// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m33
161void DOMMatrix::set_m33(double value)
162{
163 // For the DOMMatrix interface, setting the m33 attribute must set the m33 element to the new value and, if the new value is not 1, set is 2D to false.
164 m_matrix.elements()[2][2] = value;
165 if (value != 1.0)
166 m_is_2d = false;
167}
168
169// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m34
170void DOMMatrix::set_m34(double value)
171{
172 // For the DOMMatrix interface, setting the m34 attribute must set the m34 element to the new value and, if the new value is not 0 or -0, set is 2D to false.
173 m_matrix.elements()[2][3] = value;
174 if (value != 0.0 && value != -0.0)
175 m_is_2d = false;
176}
177
178// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m41
179void DOMMatrix::set_m41(double value)
180{
181 // For the DOMMatrix interface, setting the m41 or the e attribute must set the m41 element to the new value.
182 m_matrix.elements()[3][0] = value;
183}
184
185// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m42
186void DOMMatrix::set_m42(double value)
187{
188 // For the DOMMatrix interface, setting the m42 or the f attribute must set the m42 element to the new value.
189 m_matrix.elements()[3][1] = value;
190}
191
192// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m43
193void DOMMatrix::set_m43(double value)
194{
195 // For the DOMMatrix interface, setting the m43 attribute must set the m43 element to the new value and, if the new value is not 0 or -0, set is 2D to false.
196 m_matrix.elements()[3][2] = value;
197 if (value != 0.0 && value != -0.0)
198 m_is_2d = false;
199}
200
201// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m44
202void DOMMatrix::set_m44(double value)
203{
204 // For the DOMMatrix interface, setting the m44 attribute must set the m44 element to the new value and, if the new value is not 1, set is 2D to false.
205 m_matrix.elements()[3][3] = value;
206 if (value != 1.0)
207 m_is_2d = false;
208}
209
210// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-a
211void DOMMatrix::set_a(double value)
212{
213 // For the DOMMatrix interface, setting the m11 or the a attribute must set the m11 element to the new value.
214 set_m11(value);
215}
216
217// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-b
218void DOMMatrix::set_b(double value)
219{
220 // For the DOMMatrix interface, setting the m12 or the b attribute must set the m12 element to the new value.
221 set_m12(value);
222}
223
224// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-c
225void DOMMatrix::set_c(double value)
226{
227 // For the DOMMatrix interface, setting the m21 or the c attribute must set the m21 element to the new value.
228 set_m21(value);
229}
230
231// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-d
232void DOMMatrix::set_d(double value)
233{
234 // For the DOMMatrix interface, setting the m22 or the d attribute must set the m22 element to the new value.
235 set_m22(value);
236}
237
238// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-e
239void DOMMatrix::set_e(double value)
240{
241 // For the DOMMatrix interface, setting the m41 or the e attribute must set the m41 element to the new value.
242 set_m41(value);
243}
244
245// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-f
246void DOMMatrix::set_f(double value)
247{
248 // For the DOMMatrix interface, setting the m42 or the f attribute must set the m42 element to the new value.
249 set_m42(value);
250}
251
252// https://drafts.fxtf.org/geometry/#dom-dommatrix-invertself
253JS::NonnullGCPtr<DOMMatrix> DOMMatrix::invert_self()
254{
255 // 1. Invert the current matrix.
256 m_matrix = m_matrix.inverse();
257
258 // 2. If the current matrix is not invertible set all attributes to NaN and set is 2D to false.
259 if (!m_matrix.is_invertible()) {
260 for (u8 i = 0; i < 4; i++) {
261 for (u8 j = 0; j < 4; j++)
262 m_matrix.elements()[i][j] = NAN;
263 }
264 m_is_2d = false;
265 }
266
267 // 3. Return the current matrix.
268 return *this;
269}
270
271}