summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb/Geometry
diff options
context:
space:
mode:
authorLuke Wilde <lukew@serenityos.org>2023-02-27 18:04:51 +0000
committerAndreas Kling <kling@serenityos.org>2023-02-27 20:55:09 +0100
commita90667e79c4f17c2bea1a60c5e588c52659398d3 (patch)
tree4e694f17318748b9cfc02056a2d4e93a64392c24 /Userland/Libraries/LibWeb/Geometry
parente3a9ed0c267990b6e517ca47e7c436146327ba4d (diff)
downloadserenity-a90667e79c4f17c2bea1a60c5e588c52659398d3.zip
LibWeb: Add initial implementation of DOMMatrix(ReadOnly)
This is currently missing a lot of functions and initialisation from a <transform-list> string, but is enough for Ruffle.
Diffstat (limited to 'Userland/Libraries/LibWeb/Geometry')
-rw-r--r--Userland/Libraries/LibWeb/Geometry/DOMMatrix.cpp269
-rw-r--r--Userland/Libraries/LibWeb/Geometry/DOMMatrix.h58
-rw-r--r--Userland/Libraries/LibWeb/Geometry/DOMMatrix.idl52
-rw-r--r--Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.cpp493
-rw-r--r--Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.h107
-rw-r--r--Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.idl90
6 files changed, 1069 insertions, 0 deletions
diff --git a/Userland/Libraries/LibWeb/Geometry/DOMMatrix.cpp b/Userland/Libraries/LibWeb/Geometry/DOMMatrix.cpp
new file mode 100644
index 0000000000..80c584807e
--- /dev/null
+++ b/Userland/Libraries/LibWeb/Geometry/DOMMatrix.cpp
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibWeb/Bindings/Intrinsics.h>
+#include <LibWeb/Geometry/DOMMatrix.h>
+#include <LibWeb/WebIDL/ExceptionOr.h>
+
+namespace Web::Geometry {
+
+WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrix>> DOMMatrix::construct_impl(JS::Realm& realm, Optional<Variant<String, Vector<double>>> const& init)
+{
+ // https://drafts.fxtf.org/geometry/#dom-dommatrix-dommatrix
+ if (init.has_value()) {
+ // -> Otherwise
+ // Throw a TypeError exception.
+ // The only condition where this can be met is with a sequence type which doesn't have exactly 6 or 16 elements.
+ if (auto* double_sequence = init.value().get_pointer<Vector<double>>(); double_sequence && (double_sequence->size() != 6 && double_sequence->size() != 16))
+ return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, DeprecatedString::formatted("Sequence must contain exactly 6 or 16 elements, got {} element(s)", double_sequence->size()) };
+ }
+
+ return realm.heap().allocate<DOMMatrix>(realm, realm, init).release_allocated_value_but_fixme_should_propagate_errors();
+}
+
+// https://drafts.fxtf.org/geometry/#create-a-dommatrix-from-the-2d-dictionary
+WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrix>> DOMMatrix::create_from_dom_matrix_2d_init(JS::Realm& realm, DOMMatrix2DInit& init)
+{
+ // 1. Validate and fixup (2D) other.
+ TRY(validate_and_fixup_dom_matrix_2d_init(init));
+
+ // These should all have values after calling `validate_and_fixup_dom_matrix_2d_init`
+ VERIFY(init.m11.has_value());
+ VERIFY(init.m12.has_value());
+ VERIFY(init.m21.has_value());
+ VERIFY(init.m22.has_value());
+ VERIFY(init.m41.has_value());
+ VERIFY(init.m42.has_value());
+
+ // 2. Return the result of invoking create a 2d matrix of type DOMMatrixReadOnly or DOMMatrix as appropriate, with a sequence of numbers,
+ // the values being the 6 elements m11, m12, m21, m22, m41 and m42 of other in the given order.
+ 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();
+}
+
+JS::NonnullGCPtr<DOMMatrix> DOMMatrix::create_from_dom_matrix_read_only(JS::Realm& realm, DOMMatrixReadOnly const& read_only_matrix)
+{
+ return realm.heap().allocate<DOMMatrix>(realm, realm, read_only_matrix).release_allocated_value_but_fixme_should_propagate_errors();
+}
+
+DOMMatrix::DOMMatrix(JS::Realm& realm, double m11, double m12, double m21, double m22, double m41, double m42)
+ : DOMMatrixReadOnly(realm, m11, m12, m21, m22, m41, m42)
+{
+}
+
+DOMMatrix::DOMMatrix(JS::Realm& realm, Optional<Variant<String, Vector<double>>> const& init)
+ : DOMMatrixReadOnly(realm, init)
+{
+}
+
+DOMMatrix::DOMMatrix(JS::Realm& realm, DOMMatrixReadOnly const& read_only_matrix)
+ : DOMMatrixReadOnly(realm, read_only_matrix)
+{
+}
+
+DOMMatrix::~DOMMatrix() = default;
+
+JS::ThrowCompletionOr<void> DOMMatrix::initialize(JS::Realm& realm)
+{
+ MUST_OR_THROW_OOM(Base::initialize(realm));
+ set_prototype(&Bindings::ensure_web_prototype<Bindings::DOMMatrixPrototype>(realm, "DOMMatrix"));
+
+ return {};
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m11
+void DOMMatrix::set_m11(double value)
+{
+ // For the DOMMatrix interface, setting the m11 or the a attribute must set the m11 element to the new value.
+ m_matrix.elements()[0][0] = value;
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m12
+void DOMMatrix::set_m12(double value)
+{
+ // For the DOMMatrix interface, setting the m12 or the b attribute must set the m12 element to the new value.
+ m_matrix.elements()[0][1] = value;
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m13
+void DOMMatrix::set_m13(double value)
+{
+ // 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.
+ m_matrix.elements()[0][2] = value;
+ if (value != 0.0 && value != -0.0)
+ m_is_2d = false;
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m14
+void DOMMatrix::set_m14(double value)
+{
+ // 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.
+ m_matrix.elements()[0][3] = value;
+ if (value != 0.0 && value != -0.0)
+ m_is_2d = false;
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m21
+void DOMMatrix::set_m21(double value)
+{
+ // For the DOMMatrix interface, setting the m21 or the c attribute must set the m21 element to the new value.
+ m_matrix.elements()[1][0] = value;
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m22
+void DOMMatrix::set_m22(double value)
+{
+ // For the DOMMatrix interface, setting the m22 or the d attribute must set the m22 element to the new value.
+ m_matrix.elements()[1][1] = value;
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m23
+void DOMMatrix::set_m23(double value)
+{
+ // 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.
+ m_matrix.elements()[1][2] = value;
+ if (value != 0.0 && value != -0.0)
+ m_is_2d = false;
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m24
+void DOMMatrix::set_m24(double value)
+{
+ // 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.
+ m_matrix.elements()[1][3] = value;
+ if (value != 0.0 && value != -0.0)
+ m_is_2d = false;
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m31
+void DOMMatrix::set_m31(double value)
+{
+ // 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.
+ m_matrix.elements()[2][0] = value;
+ if (value != 0.0 && value != -0.0)
+ m_is_2d = false;
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m32
+void DOMMatrix::set_m32(double value)
+{
+ // 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.
+ m_matrix.elements()[2][1] = value;
+ if (value != 0.0 && value != -0.0)
+ m_is_2d = false;
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m33
+void DOMMatrix::set_m33(double value)
+{
+ // 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.
+ m_matrix.elements()[2][2] = value;
+ if (value != 1.0)
+ m_is_2d = false;
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m34
+void DOMMatrix::set_m34(double value)
+{
+ // 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.
+ m_matrix.elements()[2][3] = value;
+ if (value != 0.0 && value != -0.0)
+ m_is_2d = false;
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m41
+void DOMMatrix::set_m41(double value)
+{
+ // For the DOMMatrix interface, setting the m41 or the e attribute must set the m41 element to the new value.
+ m_matrix.elements()[3][0] = value;
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m42
+void DOMMatrix::set_m42(double value)
+{
+ // For the DOMMatrix interface, setting the m42 or the f attribute must set the m42 element to the new value.
+ m_matrix.elements()[3][1] = value;
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m43
+void DOMMatrix::set_m43(double value)
+{
+ // 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.
+ m_matrix.elements()[3][2] = value;
+ if (value != 0.0 && value != -0.0)
+ m_is_2d = false;
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-m44
+void DOMMatrix::set_m44(double value)
+{
+ // 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.
+ m_matrix.elements()[3][3] = value;
+ if (value != 1.0)
+ m_is_2d = false;
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-a
+void DOMMatrix::set_a(double value)
+{
+ // For the DOMMatrix interface, setting the m11 or the a attribute must set the m11 element to the new value.
+ set_m11(value);
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-b
+void DOMMatrix::set_b(double value)
+{
+ // For the DOMMatrix interface, setting the m12 or the b attribute must set the m12 element to the new value.
+ set_m12(value);
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-c
+void DOMMatrix::set_c(double value)
+{
+ // For the DOMMatrix interface, setting the m21 or the c attribute must set the m21 element to the new value.
+ set_m21(value);
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-d
+void DOMMatrix::set_d(double value)
+{
+ // For the DOMMatrix interface, setting the m22 or the d attribute must set the m22 element to the new value.
+ set_m22(value);
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-e
+void DOMMatrix::set_e(double value)
+{
+ // For the DOMMatrix interface, setting the m41 or the e attribute must set the m41 element to the new value.
+ set_m41(value);
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-f
+void DOMMatrix::set_f(double value)
+{
+ // For the DOMMatrix interface, setting the m42 or the f attribute must set the m42 element to the new value.
+ set_m42(value);
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrix-invertself
+JS::NonnullGCPtr<DOMMatrix> DOMMatrix::invert_self()
+{
+ // 1. Invert the current matrix.
+ m_matrix = m_matrix.inverse();
+
+ // 2. If the current matrix is not invertible set all attributes to NaN and set is 2D to false.
+ if (!m_matrix.is_invertible()) {
+ for (u8 i = 0; i < 4; i++) {
+ for (u8 j = 0; j < 4; j++)
+ m_matrix.elements()[i][j] = NAN;
+ }
+ m_is_2d = false;
+ }
+
+ // 3. Return the current matrix.
+ return *this;
+}
+
+}
diff --git a/Userland/Libraries/LibWeb/Geometry/DOMMatrix.h b/Userland/Libraries/LibWeb/Geometry/DOMMatrix.h
new file mode 100644
index 0000000000..b6527cd3e9
--- /dev/null
+++ b/Userland/Libraries/LibWeb/Geometry/DOMMatrix.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibWeb/Geometry/DOMMatrixReadOnly.h>
+
+namespace Web::Geometry {
+
+// https://drafts.fxtf.org/geometry/#dommatrix
+class DOMMatrix : public DOMMatrixReadOnly {
+ WEB_PLATFORM_OBJECT(DOMMatrix, Bindings::PlatformObject);
+
+public:
+ static WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrix>> construct_impl(JS::Realm&, Optional<Variant<String, Vector<double>>> const& init);
+ static WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrix>> create_from_dom_matrix_2d_init(JS::Realm&, DOMMatrix2DInit& init);
+ static JS::NonnullGCPtr<DOMMatrix> create_from_dom_matrix_read_only(JS::Realm&, DOMMatrixReadOnly const& read_only_matrix);
+
+ virtual ~DOMMatrix() override;
+
+ void set_m11(double value);
+ void set_m12(double value);
+ void set_m13(double value);
+ void set_m14(double value);
+ void set_m21(double value);
+ void set_m22(double value);
+ void set_m23(double value);
+ void set_m24(double value);
+ void set_m31(double value);
+ void set_m32(double value);
+ void set_m33(double value);
+ void set_m34(double value);
+ void set_m41(double value);
+ void set_m42(double value);
+ void set_m43(double value);
+ void set_m44(double value);
+
+ void set_a(double value);
+ void set_b(double value);
+ void set_c(double value);
+ void set_d(double value);
+ void set_e(double value);
+ void set_f(double value);
+
+ JS::NonnullGCPtr<DOMMatrix> invert_self();
+
+private:
+ DOMMatrix(JS::Realm&, double m11, double m12, double m21, double m22, double m41, double m42);
+ DOMMatrix(JS::Realm&, Optional<Variant<String, Vector<double>>> const& init);
+ DOMMatrix(JS::Realm&, DOMMatrixReadOnly const& read_only_matrix);
+
+ virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override;
+};
+
+}
diff --git a/Userland/Libraries/LibWeb/Geometry/DOMMatrix.idl b/Userland/Libraries/LibWeb/Geometry/DOMMatrix.idl
new file mode 100644
index 0000000000..0adc0e8d7d
--- /dev/null
+++ b/Userland/Libraries/LibWeb/Geometry/DOMMatrix.idl
@@ -0,0 +1,52 @@
+#import <Geometry/DOMMatrixReadOnly.idl>
+
+// https://drafts.fxtf.org/geometry/#dommatrix
+// FIXME: LegacyWindowAlias currently doesn't do anything.
+[Exposed=(Window,Worker), Serializable, LegacyWindowAlias=(SVGMatrix, WebKitCSSMatrix), UseNewAKString]
+interface DOMMatrix : DOMMatrixReadOnly {
+ constructor(optional (DOMString or sequence<unrestricted double>) init);
+
+ // FIXME: [NewObject] static DOMMatrix fromMatrix(optional DOMMatrixInit other = {});
+ // FIXME: [NewObject] static DOMMatrix fromFloat32Array(Float32Array array32);
+ // FIXME: [NewObject] static DOMMatrix fromFloat64Array(Float64Array array64);
+
+ // These attributes are simple aliases for certain elements of the 4x4 matrix
+ inherit attribute unrestricted double a;
+ inherit attribute unrestricted double b;
+ inherit attribute unrestricted double c;
+ inherit attribute unrestricted double d;
+ inherit attribute unrestricted double e;
+ inherit attribute unrestricted double f;
+
+ inherit attribute unrestricted double m11;
+ inherit attribute unrestricted double m12;
+ inherit attribute unrestricted double m13;
+ inherit attribute unrestricted double m14;
+ inherit attribute unrestricted double m21;
+ inherit attribute unrestricted double m22;
+ inherit attribute unrestricted double m23;
+ inherit attribute unrestricted double m24;
+ inherit attribute unrestricted double m31;
+ inherit attribute unrestricted double m32;
+ inherit attribute unrestricted double m33;
+ inherit attribute unrestricted double m34;
+ inherit attribute unrestricted double m41;
+ inherit attribute unrestricted double m42;
+ inherit attribute unrestricted double m43;
+ inherit attribute unrestricted double m44;
+
+ // Mutable transform methods
+ // FIXME: DOMMatrix multiplySelf(optional DOMMatrixInit other = {});
+ // FIXME: DOMMatrix preMultiplySelf(optional DOMMatrixInit other = {});
+ // FIXME: DOMMatrix translateSelf(optional unrestricted double tx = 0, optional unrestricted double ty = 0, optional unrestricted double tz = 0);
+ // FIXME: DOMMatrix scaleSelf(optional unrestricted double scaleX = 1, optional unrestricted double scaleY, optional unrestricted double scaleZ = 1, optional unrestricted double originX = 0, optional unrestricted double originY = 0, optional unrestricted double originZ = 0);
+ // FIXME: DOMMatrix scale3dSelf(optional unrestricted double scale = 1, optional unrestricted double originX = 0, optional unrestricted double originY = 0, optional unrestricted double originZ = 0);
+ // FIXME: DOMMatrix rotateSelf(optional unrestricted double rotX = 0, optional unrestricted double rotY, optional unrestricted double rotZ);
+ // FIXME: DOMMatrix rotateFromVectorSelf(optional unrestricted double x = 0, optional unrestricted double y = 0);
+ // FIXME: DOMMatrix rotateAxisAngleSelf(optional unrestricted double x = 0, optional unrestricted double y = 0, optional unrestricted double z = 0, optional unrestricted double angle = 0);
+ // FIXME: DOMMatrix skewXSelf(optional unrestricted double sx = 0);
+ // FIXME: DOMMatrix skewYSelf(optional unrestricted double sy = 0);
+ DOMMatrix invertSelf();
+
+ // FIXME: [Exposed=Window] DOMMatrix setMatrixValue(DOMString transformList);
+};
diff --git a/Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.cpp b/Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.cpp
new file mode 100644
index 0000000000..afc3095541
--- /dev/null
+++ b/Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.cpp
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibWeb/Bindings/Intrinsics.h>
+#include <LibWeb/Geometry/DOMMatrix.h>
+#include <LibWeb/Geometry/DOMMatrixReadOnly.h>
+#include <LibWeb/WebIDL/ExceptionOr.h>
+
+namespace Web::Geometry {
+
+WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrixReadOnly>> DOMMatrixReadOnly::construct_impl(JS::Realm& realm, Optional<Variant<String, Vector<double>>> const& init)
+{
+ // https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-dommatrixreadonly
+ if (init.has_value()) {
+ // -> Otherwise
+ // Throw a TypeError exception.
+ // The only condition where this can be met is with a sequence type which doesn't have exactly 6 or 16 elements.
+ if (auto* double_sequence = init.value().get_pointer<Vector<double>>(); double_sequence && (double_sequence->size() != 6 && double_sequence->size() != 16))
+ return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, DeprecatedString::formatted("Sequence must contain exactly 6 or 16 elements, got {} element(s)", double_sequence->size()) };
+ }
+
+ return realm.heap().allocate<DOMMatrixReadOnly>(realm, realm, init).release_allocated_value_but_fixme_should_propagate_errors();
+}
+
+// https://drafts.fxtf.org/geometry/#create-a-dommatrixreadonly-from-the-2d-dictionary
+WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrixReadOnly>> DOMMatrixReadOnly::create_from_dom_matrix_2d_init(JS::Realm& realm, DOMMatrix2DInit& init)
+{
+ // 1. Validate and fixup (2D) other.
+ TRY(validate_and_fixup_dom_matrix_2d_init(init));
+
+ // These should all have values after calling `validate_and_fixup_dom_matrix_2d_init`
+ VERIFY(init.m11.has_value());
+ VERIFY(init.m12.has_value());
+ VERIFY(init.m21.has_value());
+ VERIFY(init.m22.has_value());
+ VERIFY(init.m41.has_value());
+ VERIFY(init.m42.has_value());
+
+ // 2. Return the result of invoking create a 2d matrix of type DOMMatrixReadOnly or DOMMatrix as appropriate, with a sequence of numbers,
+ // the values being the 6 elements m11, m12, m21, m22, m41 and m42 of other in the given order.
+ return realm.heap().allocate<DOMMatrixReadOnly>(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();
+}
+
+DOMMatrixReadOnly::DOMMatrixReadOnly(JS::Realm& realm, double m11, double m12, double m21, double m22, double m41, double m42)
+ : Bindings::PlatformObject(realm)
+{
+ initialize_from_create_2d_matrix(m11, m12, m21, m22, m41, m42);
+}
+
+DOMMatrixReadOnly::DOMMatrixReadOnly(JS::Realm& 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)
+ : Bindings::PlatformObject(realm)
+{
+ initialize_from_create_3d_matrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
+}
+
+DOMMatrixReadOnly::DOMMatrixReadOnly(JS::Realm& realm, Optional<Variant<String, Vector<double>>> const& init)
+ : Bindings::PlatformObject(realm)
+{
+ // https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-dommatrixreadonly
+ // -> If init is omitted
+ if (!init.has_value()) {
+ // Return the result of invoking create a 2d matrix of type DOMMatrixReadOnly or DOMMatrix as appropriate, with the sequence [1, 0, 0, 1, 0, 0].
+ initialize_from_create_2d_matrix(1, 0, 0, 1, 0, 0);
+ return;
+ }
+ auto const& init_value = init.value();
+
+ // -> If init is a DOMString
+ if (init_value.has<String>()) {
+ dbgln("FIXME: Implement initializing DOMMatrix(ReadOnly) from DOMString: '{}'", init_value.get<String>());
+ // NOTE: This will result in an identity matrix for now.
+ return;
+ }
+
+ auto const& double_sequence = init_value.get<Vector<double>>();
+
+ // -> If init is a sequence with 6 elements
+ if (double_sequence.size() == 6) {
+ // Return the result of invoking create a 2d matrix of type DOMMatrixReadOnly or DOMMatrix as appropriate, with the sequence init.
+ initialize_from_create_2d_matrix(double_sequence[0], double_sequence[1], double_sequence[2], double_sequence[3], double_sequence[4], double_sequence[5]);
+ return;
+ }
+
+ // -> If init is a sequence with 16 elements
+ // NOTE: The "otherwise" case should be handled in construct_impl, leaving the only other possible condition here to be 16 elements.
+ VERIFY(double_sequence.size() == 16);
+
+ // Return the result of invoking create a 3d matrix of type DOMMatrixReadOnly or DOMMatrix as appropriate, with the sequence init.
+ initialize_from_create_3d_matrix(
+ double_sequence[0], double_sequence[1], double_sequence[2], double_sequence[3],
+ double_sequence[4], double_sequence[5], double_sequence[6], double_sequence[7],
+ double_sequence[8], double_sequence[9], double_sequence[10], double_sequence[11],
+ double_sequence[12], double_sequence[13], double_sequence[14], double_sequence[15]);
+}
+
+DOMMatrixReadOnly::DOMMatrixReadOnly(JS::Realm& realm, DOMMatrixReadOnly const& other)
+ : Bindings::PlatformObject(realm)
+ , m_matrix(other.m_matrix)
+ , m_is_2d(other.m_is_2d)
+{
+}
+
+DOMMatrixReadOnly::~DOMMatrixReadOnly() = default;
+
+JS::ThrowCompletionOr<void> DOMMatrixReadOnly::initialize(JS::Realm& realm)
+{
+ MUST_OR_THROW_OOM(Base::initialize(realm));
+ set_prototype(&Bindings::ensure_web_prototype<Bindings::DOMMatrixReadOnlyPrototype>(realm, "DOMMatrixReadOnly"));
+
+ return {};
+}
+
+// https://drafts.fxtf.org/geometry/#create-a-2d-matrix
+void DOMMatrixReadOnly::initialize_from_create_2d_matrix(double m11, double m12, double m21, double m22, double m41, double m42)
+{
+ // 1. Let matrix be a new instance of type.
+ // 2. Set m11 element, m12 element, m21 element, m22 element, m41 element and m42 element to the values of init in order starting with the first value.
+ auto* elements = m_matrix.elements();
+ elements[0][0] = m11;
+ elements[0][1] = m12;
+ elements[1][0] = m21;
+ elements[1][1] = m22;
+ elements[3][0] = m41;
+ elements[3][1] = m42;
+
+ // 3. Set m13 element, m14 element, m23 element, m24 element, m31 element, m32 element, m34 element, and m43 element to 0.
+ elements[0][2] = 0.0;
+ elements[0][3] = 0.0;
+ elements[1][2] = 0.0;
+ elements[1][3] = 0.0;
+ elements[2][0] = 0.0;
+ elements[2][1] = 0.0;
+ elements[2][3] = 0.0;
+ elements[3][2] = 0.0;
+
+ // 4. Set m33 element and m44 element to 1.
+ elements[2][2] = 1.0;
+ elements[3][3] = 1.0;
+
+ // 5. Set is 2D to true.
+ m_is_2d = true;
+
+ // 6. Return matrix
+}
+
+// https://drafts.fxtf.org/geometry/#create-a-3d-matrix
+void DOMMatrixReadOnly::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)
+{
+ // 1. Let matrix be a new instance of type.
+ // 2. Set m11 element to m44 element to the values of init in column-major order.
+ auto* elements = m_matrix.elements();
+ elements[0][0] = m11;
+ elements[0][1] = m12;
+ elements[0][2] = m13;
+ elements[0][3] = m14;
+ elements[1][0] = m21;
+ elements[1][1] = m22;
+ elements[1][2] = m23;
+ elements[1][3] = m24;
+ elements[2][0] = m31;
+ elements[2][1] = m32;
+ elements[2][2] = m33;
+ elements[2][3] = m34;
+ elements[3][0] = m41;
+ elements[3][1] = m42;
+ elements[3][2] = m43;
+ elements[3][3] = m44;
+
+ // 3. Set is 2D to false.
+ m_is_2d = false;
+
+ // 4. Return matrix
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-isidentity
+bool DOMMatrixReadOnly::is_identity() const
+{
+ // The isIdentity attribute must return true if
+ // m12 element, m13 element, m14 element,
+ // m21 element, m23 element, m24 element,
+ // m31 element, m32 element, m34 element
+ // m41 element, m42 element, m43 element
+ // are 0 or -0 and
+ // m11 element, m22 element, m33 element, m44 element are 1.
+ // Otherwise it must return false.
+ if (m12() != 0.0 && m12() != -0.0)
+ return false;
+
+ if (m13() != 0.0 && m13() != -0.0)
+ return false;
+
+ if (m14() != 0.0 && m14() != -0.0)
+ return false;
+
+ if (m21() != 0.0 && m21() != -0.0)
+ return false;
+
+ if (m23() != 0.0 && m24() != -0.0)
+ return false;
+
+ if (m31() != 0.0 && m32() != -0.0)
+ return false;
+
+ if (m34() != 0.0 && m34() != -0.0)
+ return false;
+
+ if (m41() != 0.0 && m42() != -0.0)
+ return false;
+
+ if (m43() != 0.0 && m43() != -0.0)
+ return false;
+
+ if (m11() != 1.0)
+ return false;
+
+ if (m22() != 1.0)
+ return false;
+
+ if (m33() != 1.0)
+ return false;
+
+ if (m44() != 1.0)
+ return false;
+
+ return true;
+}
+
+// https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-inverse
+JS::NonnullGCPtr<DOMMatrix> DOMMatrixReadOnly::inverse() const
+{
+ // 1. Let result be the resulting matrix initialized to the values of the current matrix.
+ auto result = DOMMatrix::create_from_dom_matrix_read_only(realm(), *this);
+
+ // 2. Perform a invertSelf() transformation on result.
+ // 3. Return result.
+ // The current matrix is not modified.
+ return result->invert_self();
+}
+
+// https://drafts.fxtf.org/geometry/#dommatrixreadonly-stringification-behavior
+WebIDL::ExceptionOr<String> DOMMatrixReadOnly::to_string() const
+{
+ auto& vm = this->vm();
+
+ // 1. If one or more of m11 element through m44 element are a non-finite value, then throw an "InvalidStateError" DOMException.
+ // Spec Note: The CSS syntax cannot represent NaN or Infinity values.
+ if (!isfinite(m11()) || !isfinite(m12()) || !isfinite(m13()) || !isfinite(m14())
+ || !isfinite(m21()) || !isfinite(m22()) || !isfinite(m23()) || !isfinite(m24())
+ || !isfinite(m31()) || !isfinite(m32()) || !isfinite(m33()) || !isfinite(m34())
+ || !isfinite(m41()) || !isfinite(m42()) || !isfinite(m43()) || !isfinite(m44())) {
+ return WebIDL::InvalidStateError::create(realm(), "Cannot stringify non-finite matrix values");
+ }
+
+ // 2. Let string be the empty string.
+ StringBuilder builder;
+
+ // 3. If is 2D is true, then:
+ if (m_is_2d) {
+ // 1. Append "matrix(" to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append("matrix("sv));
+
+ // 2. Append ! ToString(m11 element) to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::Value(m11()).to_string_without_side_effects())));
+
+ // 3. Append ", " to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(", "sv));
+
+ // 4. Append ! ToString(m12 element) to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::Value(m12()).to_string_without_side_effects())));
+
+ // 5. Append ", " to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(", "sv));
+
+ // 6. Append ! ToString(m21 element) to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::Value(m21()).to_string_without_side_effects())));
+
+ // 7. Append ", " to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(", "sv));
+
+ // 8. Append ! ToString(m22 element) to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::Value(m22()).to_string_without_side_effects())));
+
+ // 9. Append ", " to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(", "sv));
+
+ // 10. Append ! ToString(m41 element) to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::Value(m41()).to_string_without_side_effects())));
+
+ // 11. Append ", " to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(", "sv));
+
+ // 12. Append ! ToString(m42 element) to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::Value(m42()).to_string_without_side_effects())));
+
+ // 13. Append ")" to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(")"sv));
+ } else {
+ // 1. Append "matrix3d(" to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append("matrix3d("sv));
+
+ // 2. Append ! ToString(m11 element) to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::number_to_string(m11()))));
+
+ // 3. Append ", " to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(", "sv));
+
+ // 4. Append ! ToString(m12 element) to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::number_to_string(m12()))));
+
+ // 5. Append ", " to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(", "sv));
+
+ // 6. Append ! ToString(m13 element) to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::number_to_string(m13()))));
+
+ // 7. Append ", " to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(", "sv));
+
+ // 8. Append ! ToString(m14 element) to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::number_to_string(m14()))));
+
+ // 9. Append ", " to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(", "sv));
+
+ // 10. Append ! ToString(m21 element) to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::number_to_string(m21()))));
+
+ // 11. Append ", " to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(", "sv));
+
+ // 12. Append ! ToString(m22 element) to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::number_to_string(m22()))));
+
+ // 13. Append ", " to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(", "sv));
+
+ // 14. Append ! ToString(m23 element) to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::number_to_string(m23()))));
+
+ // 15. Append ", " to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(", "sv));
+
+ // 16. Append ! ToString(m24 element) to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::number_to_string(m24()))));
+
+ // 17. Append ", " to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(", "sv));
+
+ // NOTE: The spec doesn't include the steps to append m31 to m34, but they are required as matrix3d requires 16 elements.
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::number_to_string(m31()))));
+ TRY_OR_THROW_OOM(vm, builder.try_append(", "sv));
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::number_to_string(m32()))));
+ TRY_OR_THROW_OOM(vm, builder.try_append(", "sv));
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::number_to_string(m33()))));
+ TRY_OR_THROW_OOM(vm, builder.try_append(", "sv));
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::number_to_string(m34()))));
+ TRY_OR_THROW_OOM(vm, builder.try_append(", "sv));
+
+ // 18. Append ! ToString(m41 element) to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::number_to_string(m41()))));
+
+ // 19. Append ", " to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(", "sv));
+
+ // 20. Append ! ToString(m42 element) to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::number_to_string(m42()))));
+
+ // 21. Append ", " to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(", "sv));
+
+ // 22. Append ! ToString(m43 element) to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::number_to_string(m43()))));
+
+ // 23. Append ", " to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(", "sv));
+
+ // 24. Append ! ToString(m44 element) to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(TRY_OR_THROW_OOM(vm, JS::number_to_string(m44()))));
+
+ // 25. Append ")" to string.
+ TRY_OR_THROW_OOM(vm, builder.try_append(")"sv));
+ }
+
+ // 5. Return string.
+ return TRY_OR_THROW_OOM(vm, builder.to_string());
+}
+
+// https://drafts.fxtf.org/geometry/#matrix-validate-and-fixup-2d
+WebIDL::ExceptionOr<void> validate_and_fixup_dom_matrix_2d_init(DOMMatrix2DInit& init)
+{
+ // 1. If at least one of the following conditions are true for dict, then throw a TypeError exception and abort these steps.
+ // - a and m11 are both present and SameValueZero(a, m11) is false.
+ if (init.a.has_value() && init.m11.has_value() && !JS::same_value_zero(JS::Value(init.a.value()), JS::Value(init.m11.value())))
+ return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "DOMMatrix2DInit.a and DOMMatrix2DInit.m11 must have the same value if they are both present" };
+
+ // - b and m12 are both present and SameValueZero(b, m12) is false.
+ if (init.b.has_value() && init.m12.has_value() && !JS::same_value_zero(JS::Value(init.b.value()), JS::Value(init.m12.value())))
+ return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "DOMMatrix2DInit.b and DOMMatrix2DInit.m12 must have the same value if they are both present" };
+
+ // - c and m21 are both present and SameValueZero(c, m21) is false.
+ if (init.c.has_value() && init.m21.has_value() && !JS::same_value_zero(JS::Value(init.c.value()), JS::Value(init.m21.value())))
+ return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "DOMMatrix2DInit.c and DOMMatrix2DInit.m21 must have the same value if they are both present" };
+
+ // - d and m22 are both present and SameValueZero(d, m22) is false.
+ if (init.d.has_value() && init.m22.has_value() && !JS::same_value_zero(JS::Value(init.d.value()), JS::Value(init.m22.value())))
+ return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "DOMMatrix2DInit.d and DOMMatrix2DInit.m22 must have the same value if they are both present" };
+
+ // - e and m41 are both present and SameValueZero(e, m41) is false.
+ if (init.e.has_value() && init.m41.has_value() && !JS::same_value_zero(JS::Value(init.e.value()), JS::Value(init.m41.value())))
+ return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "DOMMatrix2DInit.e and DOMMatrix2DInit.m41 must have the same value if they are both present" };
+
+ // - f and m42 are both present and SameValueZero(f, m42) is false.
+ if (init.f.has_value() && init.m42.has_value() && !JS::same_value_zero(JS::Value(init.f.value()), JS::Value(init.m42.value())))
+ return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "DOMMatrix2DInit.f and DOMMatrix2DInit.m42 must have the same value if they are both present" };
+
+ // 2. If m11 is not present then set it to the value of member a, or value 1 if a is also not present.
+ if (!init.m11.has_value())
+ init.m11 = init.a.value_or(1.0);
+
+ // 3. If m12 is not present then set it to the value of member b, or value 0 if b is also not present.
+ if (!init.m12.has_value())
+ init.m12 = init.b.value_or(0.0);
+
+ // 4. If m21 is not present then set it to the value of member c, or value 0 if c is also not present.
+ if (!init.m21.has_value())
+ init.m21 = init.c.value_or(0.0);
+
+ // 5. If m22 is not present then set it to the value of member d, or value 1 if d is also not present.
+ if (!init.m22.has_value())
+ init.m22 = init.d.value_or(1.0);
+
+ // 6. If m41 is not present then set it to the value of member e, or value 0 if e is also not present.
+ if (!init.m41.has_value())
+ init.m41 = init.e.value_or(0.0);
+
+ // 7. If m42 is not present then set it to the value of member f, or value 0 if f is also not present.
+ if (!init.m42.has_value())
+ init.m42 = init.f.value_or(0.0);
+
+ return {};
+}
+
+// https://drafts.fxtf.org/geometry/#matrix-validate-and-fixup
+WebIDL::ExceptionOr<void> validate_and_fixup_dom_matrix_init(DOMMatrixInit& init)
+{
+ // 1. Validate and fixup (2D) dict.
+ TRY(validate_and_fixup_dom_matrix_2d_init(init));
+
+ // 2. If is2D is true and: at least one of m13, m14, m23, m24, m31, m32, m34, m43 are present with a value other than 0 or -0,
+ // or at least one of m33, m44 are present with a value other than 1, then throw a TypeError exception and abort these steps.
+ if (init.is2d.has_value() && init.is2d.value()) {
+ if ((init.m13 != 0.0 && init.m13 != -0.0)
+ || (init.m14 != 0.0 && init.m14 != -0.0)
+ || (init.m23 != 0.0 && init.m23 != -0.0)
+ || (init.m24 != 0.0 && init.m24 != -0.0)
+ || (init.m31 != 0.0 && init.m31 != -0.0)
+ || (init.m32 != 0.0 && init.m32 != -0.0)
+ || (init.m34 != 0.0 && init.m34 != -0.0)
+ || (init.m43 != 0.0 && init.m43 != -0.0)
+ || init.m33 != 1.0
+ || init.m44 != 1.0) {
+ return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "DOMMatrixInit.is2D is true, but the given matrix is not a 2D matrix" };
+ }
+ }
+
+ // If is2D is not present and at least one of m13, m14, m23, m24, m31, m32, m34, m43 are present with a value other than 0 or -0,
+ // or at least one of m33, m44 are present with a value other than 1, set is2D to false.
+ if (!init.is2d.has_value()) {
+ if ((init.m13 != 0.0 && init.m13 != -0.0)
+ || (init.m14 != 0.0 && init.m14 != -0.0)
+ || (init.m23 != 0.0 && init.m23 != -0.0)
+ || (init.m24 != 0.0 && init.m24 != -0.0)
+ || (init.m31 != 0.0 && init.m31 != -0.0)
+ || (init.m32 != 0.0 && init.m32 != -0.0)
+ || (init.m34 != 0.0 && init.m34 != -0.0)
+ || (init.m43 != 0.0 && init.m43 != -0.0)
+ || init.m33 != 1.0
+ || init.m44 != 1.0) {
+ init.is2d = false;
+ }
+ }
+
+ // 4. If is2D is still not present, set it to true.
+ if (!init.is2d.has_value())
+ init.is2d = true;
+
+ return {};
+}
+
+}
diff --git a/Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.h b/Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.h
new file mode 100644
index 0000000000..c5a9c476a2
--- /dev/null
+++ b/Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibGfx/Matrix4x4.h>
+#include <LibWeb/Bindings/PlatformObject.h>
+#include <LibWeb/Forward.h>
+
+namespace Web::Geometry {
+
+// https://drafts.fxtf.org/geometry/#dictdef-dommatrix2dinit
+struct DOMMatrix2DInit {
+ Optional<double> a;
+ Optional<double> b;
+ Optional<double> c;
+ Optional<double> d;
+ Optional<double> e;
+ Optional<double> f;
+ Optional<double> m11;
+ Optional<double> m12;
+ Optional<double> m21;
+ Optional<double> m22;
+ Optional<double> m41;
+ Optional<double> m42;
+};
+
+// https://drafts.fxtf.org/geometry/#dictdef-dommatrixinit
+struct DOMMatrixInit : public DOMMatrix2DInit {
+ double m13 { 0.0 };
+ double m14 { 0.0 };
+ double m23 { 0.0 };
+ double m24 { 0.0 };
+ double m31 { 0.0 };
+ double m32 { 0.0 };
+ double m33 { 0.0 };
+ double m34 { 0.0 };
+ double m43 { 0.0 };
+ double m44 { 0.0 };
+ Optional<bool> is2d;
+};
+
+// https://drafts.fxtf.org/geometry/#dommatrixreadonly
+class DOMMatrixReadOnly : public Bindings::PlatformObject {
+ WEB_PLATFORM_OBJECT(DOMMatrixReadOnly, Bindings::PlatformObject);
+
+public:
+ static WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrixReadOnly>> construct_impl(JS::Realm&, Optional<Variant<String, Vector<double>>> const& init);
+ static WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMMatrixReadOnly>> create_from_dom_matrix_2d_init(JS::Realm&, DOMMatrix2DInit& init);
+
+ virtual ~DOMMatrixReadOnly() override;
+
+ // https://drafts.fxtf.org/geometry/#dommatrix-attributes
+ double m11() const { return m_matrix.elements()[0][0]; }
+ double m12() const { return m_matrix.elements()[0][1]; }
+ double m13() const { return m_matrix.elements()[0][2]; }
+ double m14() const { return m_matrix.elements()[0][3]; }
+ double m21() const { return m_matrix.elements()[1][0]; }
+ double m22() const { return m_matrix.elements()[1][1]; }
+ double m23() const { return m_matrix.elements()[1][2]; }
+ double m24() const { return m_matrix.elements()[1][3]; }
+ double m31() const { return m_matrix.elements()[2][0]; }
+ double m32() const { return m_matrix.elements()[2][1]; }
+ double m33() const { return m_matrix.elements()[2][2]; }
+ double m34() const { return m_matrix.elements()[2][3]; }
+ double m41() const { return m_matrix.elements()[3][0]; }
+ double m42() const { return m_matrix.elements()[3][1]; }
+ double m43() const { return m_matrix.elements()[3][2]; }
+ double m44() const { return m_matrix.elements()[3][3]; }
+
+ double a() const { return m11(); }
+ double b() const { return m12(); }
+ double c() const { return m21(); }
+ double d() const { return m22(); }
+ double e() const { return m41(); }
+ double f() const { return m42(); }
+
+ bool is2d() const { return m_is_2d; }
+ bool is_identity() const;
+
+ JS::NonnullGCPtr<DOMMatrix> inverse() const;
+
+ WebIDL::ExceptionOr<String> to_string() const;
+
+protected:
+ DOMMatrixReadOnly(JS::Realm&, double m11, double m12, double m21, double m22, double m41, double m42);
+ 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);
+ DOMMatrixReadOnly(JS::Realm&, Optional<Variant<String, Vector<double>>> const& init);
+ DOMMatrixReadOnly(JS::Realm&, DOMMatrixReadOnly const& other);
+
+ Gfx::DoubleMatrix4x4 m_matrix { Gfx::DoubleMatrix4x4::identity() };
+ bool m_is_2d { true };
+
+private:
+ void initialize_from_create_2d_matrix(double m11, double m12, double m21, double m22, double m41, double m42);
+ 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);
+
+ virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override;
+};
+
+WebIDL::ExceptionOr<void> validate_and_fixup_dom_matrix_2d_init(DOMMatrix2DInit& init);
+WebIDL::ExceptionOr<void> validate_and_fixup_dom_matrix_init(DOMMatrixInit& init);
+
+}
diff --git a/Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.idl b/Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.idl
new file mode 100644
index 0000000000..c04c36429f
--- /dev/null
+++ b/Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.idl
@@ -0,0 +1,90 @@
+#import <Geometry/DOMMatrix.idl>
+
+// https://drafts.fxtf.org/geometry/#dommatrixreadonly
+[Exposed=(Window,Worker), Serializable, UseNewAKString]
+interface DOMMatrixReadOnly {
+ constructor(optional (DOMString or sequence<unrestricted double>) init);
+
+ // FIXME: [NewObject] static DOMMatrixReadOnly fromMatrix(optional DOMMatrixInit other = {});
+ // FIXME: [NewObject] static DOMMatrixReadOnly fromFloat32Array(Float32Array array32);
+ // FIXME: [NewObject] static DOMMatrixReadOnly fromFloat64Array(Float64Array array64);
+
+ // These attributes are simple aliases for certain elements of the 4x4 matrix
+ readonly attribute unrestricted double a;
+ readonly attribute unrestricted double b;
+ readonly attribute unrestricted double c;
+ readonly attribute unrestricted double d;
+ readonly attribute unrestricted double e;
+ readonly attribute unrestricted double f;
+
+ readonly attribute unrestricted double m11;
+ readonly attribute unrestricted double m12;
+ readonly attribute unrestricted double m13;
+ readonly attribute unrestricted double m14;
+ readonly attribute unrestricted double m21;
+ readonly attribute unrestricted double m22;
+ readonly attribute unrestricted double m23;
+ readonly attribute unrestricted double m24;
+ readonly attribute unrestricted double m31;
+ readonly attribute unrestricted double m32;
+ readonly attribute unrestricted double m33;
+ readonly attribute unrestricted double m34;
+ readonly attribute unrestricted double m41;
+ readonly attribute unrestricted double m42;
+ readonly attribute unrestricted double m43;
+ readonly attribute unrestricted double m44;
+
+ readonly attribute boolean is2D;
+ readonly attribute boolean isIdentity;
+
+ // Immutable transform methods
+ // FIXME: [NewObject] DOMMatrix translate(optional unrestricted double tx = 0, optional unrestricted double ty = 0, optional unrestricted double tz = 0);
+ // FIXME: [NewObject] DOMMatrix scale(optional unrestricted double scaleX = 1, optional unrestricted double scaleY, optional unrestricted double scaleZ = 1, optional unrestricted double originX = 0, optional unrestricted double originY = 0, optional unrestricted double originZ = 0);
+ // FIXME: [NewObject] DOMMatrix scaleNonUniform(optional unrestricted double scaleX = 1, optional unrestricted double scaleY = 1);
+ // FIXME: [NewObject] DOMMatrix scale3d(optional unrestricted double scale = 1, optional unrestricted double originX = 0, optional unrestricted double originY = 0, optional unrestricted double originZ = 0);
+ // FIXME: [NewObject] DOMMatrix rotate(optional unrestricted double rotX = 0, optional unrestricted double rotY, optional unrestricted double rotZ);
+ // FIXME: [NewObject] DOMMatrix rotateFromVector(optional unrestricted double x = 0, optional unrestricted double y = 0);
+ // FIXME: [NewObject] DOMMatrix rotateAxisAngle(optional unrestricted double x = 0, optional unrestricted double y = 0, optional unrestricted double z = 0, optional unrestricted double angle = 0);
+ // FIXME: [NewObject] DOMMatrix skewX(optional unrestricted double sx = 0);
+ // FIXME: [NewObject] DOMMatrix skewY(optional unrestricted double sy = 0);
+ // FIXME: [NewObject] DOMMatrix multiply(optional DOMMatrixInit other = {});
+ // FIXME: [NewObject] DOMMatrix flipX();
+ // FIXME: [NewObject] DOMMatrix flipY();
+ [NewObject] DOMMatrix inverse();
+
+ // FIXME: [NewObject] DOMPoint transformPoint(optional DOMPointInit point = {});
+ // FIXME: [NewObject] Float32Array toFloat32Array();
+ // FIXME: [NewObject] Float64Array toFloat64Array();
+
+ [Exposed=Window] stringifier;
+ // FIXME: [Default] object toJSON();
+};
+
+dictionary DOMMatrix2DInit {
+ unrestricted double a;
+ unrestricted double b;
+ unrestricted double c;
+ unrestricted double d;
+ unrestricted double e;
+ unrestricted double f;
+ unrestricted double m11;
+ unrestricted double m12;
+ unrestricted double m21;
+ unrestricted double m22;
+ unrestricted double m41;
+ unrestricted double m42;
+};
+
+dictionary DOMMatrixInit : DOMMatrix2DInit {
+ unrestricted double m13 = 0;
+ unrestricted double m14 = 0;
+ unrestricted double m23 = 0;
+ unrestricted double m24 = 0;
+ unrestricted double m31 = 0;
+ unrestricted double m32 = 0;
+ unrestricted double m33 = 1;
+ unrestricted double m34 = 0;
+ unrestricted double m43 = 0;
+ unrestricted double m44 = 1;
+ boolean is2D;
+};