diff --git a/Meta/gn/secondary/Userland/Libraries/LibWeb/Geometry/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibWeb/Geometry/BUILD.gn
index b30b84f2834..38fef51294c 100644
--- a/Meta/gn/secondary/Userland/Libraries/LibWeb/Geometry/BUILD.gn
+++ b/Meta/gn/secondary/Userland/Libraries/LibWeb/Geometry/BUILD.gn
@@ -6,6 +6,7 @@ source_set("Geometry") {
"DOMMatrixReadOnly.cpp",
"DOMPoint.cpp",
"DOMPointReadOnly.cpp",
+ "DOMQuad.cpp",
"DOMRect.cpp",
"DOMRectList.cpp",
"DOMRectReadOnly.cpp",
diff --git a/Meta/gn/secondary/Userland/Libraries/LibWeb/idl_files.gni b/Meta/gn/secondary/Userland/Libraries/LibWeb/idl_files.gni
index ae24b2fd683..94ea9265558 100644
--- a/Meta/gn/secondary/Userland/Libraries/LibWeb/idl_files.gni
+++ b/Meta/gn/secondary/Userland/Libraries/LibWeb/idl_files.gni
@@ -85,6 +85,7 @@ standard_idl_files = [
"//Userland/Libraries/LibWeb/Geometry/DOMMatrixReadOnly.idl",
"//Userland/Libraries/LibWeb/Geometry/DOMPoint.idl",
"//Userland/Libraries/LibWeb/Geometry/DOMPointReadOnly.idl",
+ "//Userland/Libraries/LibWeb/Geometry/DOMQuad.idl",
"//Userland/Libraries/LibWeb/Geometry/DOMRect.idl",
"//Userland/Libraries/LibWeb/Geometry/DOMRectList.idl",
"//Userland/Libraries/LibWeb/Geometry/DOMRectReadOnly.idl",
diff --git a/Tests/LibWeb/Text/expected/geometry/domquad.txt b/Tests/LibWeb/Text/expected/geometry/domquad.txt
new file mode 100644
index 00000000000..cdabfafbaed
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/geometry/domquad.txt
@@ -0,0 +1,4 @@
+1. {"p1":{"x":0,"y":0,"z":0,"w":1},"p2":{"x":100,"y":0,"z":0,"w":1},"p3":{"x":100,"y":100,"z":0,"w":1},"p4":{"x":0,"y":100,"z":0,"w":1}}
+2. {"p1":{"x":0,"y":0,"z":0,"w":1},"p2":{"x":100,"y":0,"z":0,"w":1},"p3":{"x":100,"y":100,"z":0,"w":1},"p4":{"x":0,"y":100,"z":0,"w":1}}
+3. {"p1":{"x":0,"y":0,"z":0,"w":1},"p2":{"x":100,"y":0,"z":0,"w":1},"p3":{"x":100,"y":100,"z":0,"w":1},"p4":{"x":0,"y":100,"z":0,"w":1}}
+4. {"x":0,"y":0,"width":100,"height":100,"top":0,"right":100,"bottom":100,"left":0}
diff --git a/Tests/LibWeb/Text/input/geometry/domquad.html b/Tests/LibWeb/Text/input/geometry/domquad.html
new file mode 100644
index 00000000000..c8c4ddc6807
--- /dev/null
+++ b/Tests/LibWeb/Text/input/geometry/domquad.html
@@ -0,0 +1,36 @@
+
+
diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt
index 805b473b84a..138e169f342 100644
--- a/Userland/Libraries/LibWeb/CMakeLists.txt
+++ b/Userland/Libraries/LibWeb/CMakeLists.txt
@@ -222,6 +222,7 @@ set(SOURCES
Geometry/DOMMatrixReadOnly.cpp
Geometry/DOMPoint.cpp
Geometry/DOMPointReadOnly.cpp
+ Geometry/DOMQuad.cpp
Geometry/DOMRect.cpp
Geometry/DOMRectList.cpp
Geometry/DOMRectReadOnly.cpp
diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h
index f905f2cfb81..44332d29093 100644
--- a/Userland/Libraries/LibWeb/Forward.h
+++ b/Userland/Libraries/LibWeb/Forward.h
@@ -302,6 +302,7 @@ class DOMMatrix;
class DOMMatrixReadOnly;
class DOMPoint;
class DOMPointReadOnly;
+class DOMQuad;
class DOMRect;
class DOMRectList;
class DOMRectReadOnly;
diff --git a/Userland/Libraries/LibWeb/Geometry/DOMQuad.cpp b/Userland/Libraries/LibWeb/Geometry/DOMQuad.cpp
new file mode 100644
index 00000000000..d5d59ec6bca
--- /dev/null
+++ b/Userland/Libraries/LibWeb/Geometry/DOMQuad.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2023, Bastiaan van der Plaat
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include
+#include
+
+namespace Web::Geometry {
+
+JS::NonnullGCPtr DOMQuad::construct_impl(JS::Realm& realm, DOMPointInit const& p1, DOMPointInit const& p2, DOMPointInit const& p3, DOMPointInit const& p4)
+{
+ return realm.heap().allocate(realm, realm, p1, p2, p3, p4);
+}
+
+DOMQuad::DOMQuad(JS::Realm& realm, DOMPointInit const& p1, DOMPointInit const& p2, DOMPointInit const& p3, DOMPointInit const& p4)
+ : PlatformObject(realm)
+ , m_p1(DOMPoint::from_point(realm.vm(), p1))
+ , m_p2(DOMPoint::from_point(realm.vm(), p2))
+ , m_p3(DOMPoint::from_point(realm.vm(), p3))
+ , m_p4(DOMPoint::from_point(realm.vm(), p4))
+{
+}
+
+DOMQuad::~DOMQuad() = default;
+
+// https://drafts.fxtf.org/geometry/#dom-domquad-fromrect
+JS::NonnullGCPtr DOMQuad::from_rect(JS::VM& vm, DOMRectInit const& other)
+{
+ // The fromRect(other) static method on DOMQuad must create a DOMQuad from the DOMRectInit dictionary other.
+ return construct_impl(*vm.current_realm(), { other.x, other.y },
+ { other.x + other.width, other.y },
+ { other.x + other.width, other.y + other.height },
+ { other.x, other.y + other.height });
+}
+
+// https://drafts.fxtf.org/geometry/#dom-domquad-fromquad
+JS::NonnullGCPtr DOMQuad::from_quad(JS::VM& vm, DOMQuadInit const& other)
+{
+ // The fromQuad(other) static method on DOMQuad must create a DOMQuad from the DOMQuadInit dictionary other.
+ return construct_impl(*vm.current_realm(), other.p1, other.p2, other.p3, other.p4);
+}
+
+// https://drafts.fxtf.org/geometry/#dom-domquad-getbounds
+JS::NonnullGCPtr DOMQuad::get_bounds() const
+{
+ // 1. Let bounds be a DOMRect object.
+ auto bounds = DOMRect::create(realm(), {});
+
+ // 2. Let left be the NaN-safe minimum of point 1’s x coordinate, point 2’s x coordinate, point 3’s x coordinate and point 4’s x coordinate.
+ auto left = min(m_p1->x(), min(m_p2->x(), min(m_p3->x(), m_p4->x())));
+
+ // 3. Let top be the NaN-safe minimum of point 1’s y coordinate, point 2’s y coordinate, point 3’s y coordinate and point 4’s y coordinate.
+ auto top = min(m_p1->y(), min(m_p2->y(), min(m_p3->y(), m_p4->y())));
+
+ // 4. Let right be the NaN-safe maximum of point 1’s x coordinate, point 2’s x coordinate, point 3’s x coordinate and point 4’s x coordinate.
+ auto right = max(m_p1->x(), max(m_p2->x(), max(m_p3->x(), m_p4->x())));
+
+ // 5. Let bottom be the NaN-safe maximum of point 1’s y coordinate, point 2’s y coordinate, point 3’s y coordinate and point 4’s y coordinate.
+ auto bottom = max(m_p1->y(), max(m_p2->y(), max(m_p3->y(), m_p4->y())));
+
+ // 6. Set x coordinate of bounds to left, y coordinate of bounds to top, width dimension of bounds to right - left and height dimension of bounds to bottom - top.
+ bounds->set_x(left);
+ bounds->set_y(top);
+ bounds->set_width(right - left);
+ bounds->set_height(bottom - top);
+
+ // 7. Return bounds.
+ return bounds;
+}
+
+void DOMQuad::initialize(JS::Realm& realm)
+{
+ Base::initialize(realm);
+ set_prototype(&Bindings::ensure_web_prototype(realm, "DOMQuad"));
+}
+
+void DOMQuad::visit_edges(Cell::Visitor& visitor)
+{
+ Base::visit_edges(visitor);
+ visitor.visit(m_p1.ptr());
+ visitor.visit(m_p2.ptr());
+ visitor.visit(m_p3.ptr());
+ visitor.visit(m_p4.ptr());
+}
+
+}
diff --git a/Userland/Libraries/LibWeb/Geometry/DOMQuad.h b/Userland/Libraries/LibWeb/Geometry/DOMQuad.h
new file mode 100644
index 00000000000..33df0bfae98
--- /dev/null
+++ b/Userland/Libraries/LibWeb/Geometry/DOMQuad.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2023, Bastiaan van der Plaat
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include
+#include
+#include
+#include
+
+namespace Web::Geometry {
+
+// https://drafts.fxtf.org/geometry/#dictdef-domquadinit
+struct DOMQuadInit {
+ DOMPointInit p1;
+ DOMPointInit p2;
+ DOMPointInit p3;
+ DOMPointInit p4;
+};
+
+// https://drafts.fxtf.org/geometry/#domquad
+class DOMQuad : public Bindings::PlatformObject {
+ WEB_PLATFORM_OBJECT(DOMQuad, Bindings::PlatformObject);
+
+public:
+ static JS::NonnullGCPtr construct_impl(JS::Realm&, DOMPointInit const& p1, DOMPointInit const& p2, DOMPointInit const& p3, DOMPointInit const& p4);
+
+ virtual ~DOMQuad() override;
+
+ static JS::NonnullGCPtr from_rect(JS::VM&, DOMRectInit const&);
+ static JS::NonnullGCPtr from_quad(JS::VM&, DOMQuadInit const&);
+
+ JS::NonnullGCPtr p1() const { return m_p1; }
+ JS::NonnullGCPtr p2() const { return m_p2; }
+ JS::NonnullGCPtr p3() const { return m_p3; }
+ JS::NonnullGCPtr p4() const { return m_p4; }
+
+ JS::NonnullGCPtr get_bounds() const;
+
+private:
+ DOMQuad(JS::Realm&, DOMPointInit const& p1, DOMPointInit const& p2, DOMPointInit const& p3, DOMPointInit const& p4);
+
+ virtual void initialize(JS::Realm&) override;
+ virtual void visit_edges(Cell::Visitor&) override;
+
+ JS::NonnullGCPtr m_p1;
+ JS::NonnullGCPtr m_p2;
+ JS::NonnullGCPtr m_p3;
+ JS::NonnullGCPtr m_p4;
+};
+
+}
diff --git a/Userland/Libraries/LibWeb/Geometry/DOMQuad.idl b/Userland/Libraries/LibWeb/Geometry/DOMQuad.idl
new file mode 100644
index 00000000000..78018da940d
--- /dev/null
+++ b/Userland/Libraries/LibWeb/Geometry/DOMQuad.idl
@@ -0,0 +1,28 @@
+#import
+#import
+
+// https://drafts.fxtf.org/geometry/#domquad
+[Exposed=(Window,Worker), Serializable]
+interface DOMQuad {
+ constructor(optional DOMPointInit p1 = {}, optional DOMPointInit p2 = {},
+ optional DOMPointInit p3 = {}, optional DOMPointInit p4 = {});
+
+ [NewObject] static DOMQuad fromRect(optional DOMRectInit other = {});
+ [NewObject] static DOMQuad fromQuad(optional DOMQuadInit other = {});
+
+ [SameObject] readonly attribute DOMPoint p1;
+ [SameObject] readonly attribute DOMPoint p2;
+ [SameObject] readonly attribute DOMPoint p3;
+ [SameObject] readonly attribute DOMPoint p4;
+ [NewObject] DOMRect getBounds();
+
+ [Default] object toJSON();
+};
+
+// https://drafts.fxtf.org/geometry/#dictdef-domquadinit
+dictionary DOMQuadInit {
+ DOMPointInit p1;
+ DOMPointInit p2;
+ DOMPointInit p3;
+ DOMPointInit p4;
+};
diff --git a/Userland/Libraries/LibWeb/Geometry/DOMRectReadOnly.idl b/Userland/Libraries/LibWeb/Geometry/DOMRectReadOnly.idl
index aa4da63178c..5f1f881a99b 100644
--- a/Userland/Libraries/LibWeb/Geometry/DOMRectReadOnly.idl
+++ b/Userland/Libraries/LibWeb/Geometry/DOMRectReadOnly.idl
@@ -16,6 +16,8 @@ interface DOMRectReadOnly {
readonly attribute double bottom;
readonly attribute double left;
+ [Default] object toJSON();
+
};
dictionary DOMRectInit {
diff --git a/Userland/Libraries/LibWeb/idl_files.cmake b/Userland/Libraries/LibWeb/idl_files.cmake
index 0bdb3ea6897..67ef6ac2968 100644
--- a/Userland/Libraries/LibWeb/idl_files.cmake
+++ b/Userland/Libraries/LibWeb/idl_files.cmake
@@ -71,6 +71,7 @@ libweb_js_bindings(Geometry/DOMMatrix)
libweb_js_bindings(Geometry/DOMMatrixReadOnly)
libweb_js_bindings(Geometry/DOMPoint)
libweb_js_bindings(Geometry/DOMPointReadOnly)
+libweb_js_bindings(Geometry/DOMQuad)
libweb_js_bindings(Geometry/DOMRect)
libweb_js_bindings(Geometry/DOMRectList)
libweb_js_bindings(Geometry/DOMRectReadOnly)