/src/serenity/Userland/Libraries/LibWeb/Geometry/DOMQuad.cpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2023, Bastiaan van der Plaat <bastiaan.v.d.plaat@gmail.com> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include <LibWeb/Bindings/DOMQuadPrototype.h> |
8 | | #include <LibWeb/Bindings/Intrinsics.h> |
9 | | #include <LibWeb/Geometry/DOMQuad.h> |
10 | | |
11 | | namespace Web::Geometry { |
12 | | |
13 | | JS_DEFINE_ALLOCATOR(DOMQuad); |
14 | | |
15 | | JS::NonnullGCPtr<DOMQuad> DOMQuad::construct_impl(JS::Realm& realm, DOMPointInit const& p1, DOMPointInit const& p2, DOMPointInit const& p3, DOMPointInit const& p4) |
16 | 0 | { |
17 | 0 | return realm.heap().allocate<DOMQuad>(realm, realm, p1, p2, p3, p4); |
18 | 0 | } |
19 | | |
20 | | JS::NonnullGCPtr<DOMQuad> DOMQuad::create(JS::Realm& realm) |
21 | 0 | { |
22 | 0 | return realm.heap().allocate<DOMQuad>(realm, realm); |
23 | 0 | } |
24 | | |
25 | | DOMQuad::DOMQuad(JS::Realm& realm, DOMPointInit const& p1, DOMPointInit const& p2, DOMPointInit const& p3, DOMPointInit const& p4) |
26 | 0 | : PlatformObject(realm) |
27 | 0 | , m_p1(DOMPoint::from_point(realm.vm(), p1)) |
28 | 0 | , m_p2(DOMPoint::from_point(realm.vm(), p2)) |
29 | 0 | , m_p3(DOMPoint::from_point(realm.vm(), p3)) |
30 | 0 | , m_p4(DOMPoint::from_point(realm.vm(), p4)) |
31 | 0 | { |
32 | 0 | } |
33 | | |
34 | | DOMQuad::DOMQuad(JS::Realm& realm) |
35 | 0 | : PlatformObject(realm) |
36 | 0 | , m_p1(DOMPoint::create(realm)) |
37 | 0 | , m_p2(DOMPoint::create(realm)) |
38 | 0 | , m_p3(DOMPoint::create(realm)) |
39 | 0 | , m_p4(DOMPoint::create(realm)) |
40 | 0 | { |
41 | 0 | } |
42 | | |
43 | 0 | DOMQuad::~DOMQuad() = default; |
44 | | |
45 | | // https://drafts.fxtf.org/geometry/#dom-domquad-fromrect |
46 | | JS::NonnullGCPtr<DOMQuad> DOMQuad::from_rect(JS::VM& vm, DOMRectInit const& other) |
47 | 0 | { |
48 | | // The fromRect(other) static method on DOMQuad must create a DOMQuad from the DOMRectInit dictionary other. |
49 | 0 | return construct_impl(*vm.current_realm(), { other.x, other.y }, |
50 | 0 | { other.x + other.width, other.y }, |
51 | 0 | { other.x + other.width, other.y + other.height }, |
52 | 0 | { other.x, other.y + other.height }); |
53 | 0 | } |
54 | | |
55 | | // https://drafts.fxtf.org/geometry/#dom-domquad-fromquad |
56 | | JS::NonnullGCPtr<DOMQuad> DOMQuad::from_quad(JS::VM& vm, DOMQuadInit const& other) |
57 | 0 | { |
58 | | // The fromQuad(other) static method on DOMQuad must create a DOMQuad from the DOMQuadInit dictionary other. |
59 | 0 | return construct_impl(*vm.current_realm(), other.p1, other.p2, other.p3, other.p4); |
60 | 0 | } |
61 | | |
62 | | // https://drafts.fxtf.org/geometry/#dom-domquad-getbounds |
63 | | JS::NonnullGCPtr<DOMRect> DOMQuad::get_bounds() const |
64 | 0 | { |
65 | | // The NaN-safe minimum of a non-empty list of unrestricted double values is NaN if any member of the list is NaN, or the minimum of the list otherwise. |
66 | 0 | auto nan_safe_minimum = [](double a, double b, double c, double d) -> double { |
67 | 0 | if (isnan(a) || isnan(b) || isnan(c) || isnan(d)) |
68 | 0 | return NAN; |
69 | 0 | return min(a, min(b, min(c, d))); |
70 | 0 | }; |
71 | | |
72 | | // Analogously, the NaN-safe maximum of a non-empty list of unrestricted double values is NaN if any member of the list is NaN, or the maximum of the list otherwise. |
73 | 0 | auto nan_safe_maximum = [](double a, double b, double c, double d) -> double { |
74 | 0 | if (isnan(a) || isnan(b) || isnan(c) || isnan(d)) |
75 | 0 | return NAN; |
76 | 0 | return max(a, max(b, max(c, d))); |
77 | 0 | }; |
78 | | |
79 | | // 1. Let bounds be a DOMRect object. |
80 | 0 | auto bounds = DOMRect::create(realm(), {}); |
81 | | |
82 | | // 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. |
83 | 0 | auto left = nan_safe_minimum(m_p1->x(), m_p2->x(), m_p3->x(), m_p4->x()); |
84 | | |
85 | | // 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. |
86 | 0 | auto top = nan_safe_minimum(m_p1->y(), m_p2->y(), m_p3->y(), m_p4->y()); |
87 | | |
88 | | // 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. |
89 | 0 | auto right = nan_safe_maximum(m_p1->x(), m_p2->x(), m_p3->x(), m_p4->x()); |
90 | | |
91 | | // 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. |
92 | 0 | auto bottom = nan_safe_maximum(m_p1->y(), m_p2->y(), m_p3->y(), m_p4->y()); |
93 | | |
94 | | // 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. |
95 | 0 | bounds->set_x(left); |
96 | 0 | bounds->set_y(top); |
97 | 0 | bounds->set_width(right - left); |
98 | 0 | bounds->set_height(bottom - top); |
99 | | |
100 | | // 7. Return bounds. |
101 | 0 | return bounds; |
102 | 0 | } |
103 | | |
104 | | // https://drafts.fxtf.org/geometry/#structured-serialization |
105 | | WebIDL::ExceptionOr<void> DOMQuad::serialization_steps(HTML::SerializationRecord& serialzied, bool for_storage, HTML::SerializationMemory& memory) |
106 | 0 | { |
107 | 0 | auto& vm = this->vm(); |
108 | | // 1. Set serialized.[[P1]] to the sub-serialization of value’s point 1. |
109 | 0 | serialzied.extend(TRY(HTML::structured_serialize_internal(vm, m_p1, for_storage, memory))); |
110 | | // 2. Set serialized.[[P2]] to the sub-serialization of value’s point 2. |
111 | 0 | serialzied.extend(TRY(HTML::structured_serialize_internal(vm, m_p2, for_storage, memory))); |
112 | | // 3. Set serialized.[[P3]] to the sub-serialization of value’s point 3. |
113 | 0 | serialzied.extend(TRY(HTML::structured_serialize_internal(vm, m_p3, for_storage, memory))); |
114 | | // 4. Set serialized.[[P4]] to the sub-serialization of value’s point 4. |
115 | 0 | serialzied.extend(TRY(HTML::structured_serialize_internal(vm, m_p4, for_storage, memory))); |
116 | |
|
117 | 0 | return {}; |
118 | 0 | } |
119 | | |
120 | | // https://drafts.fxtf.org/geometry/#structured-serialization |
121 | | WebIDL::ExceptionOr<void> DOMQuad::deserialization_steps(ReadonlySpan<u32> const& serialized, size_t& position, HTML::DeserializationMemory& memory) |
122 | 0 | { |
123 | 0 | auto& realm = this->realm(); |
124 | | // 1. Set value’s point 1 to the sub-deserialization of serialized.[[P1]]. |
125 | 0 | auto deserialized_record = TRY(HTML::structured_deserialize_internal(vm(), serialized, realm, memory, position)); |
126 | 0 | if (deserialized_record.value.has_value() && is<DOMPoint>(deserialized_record.value.value().as_object())) |
127 | 0 | m_p1 = dynamic_cast<DOMPoint&>(deserialized_record.value.release_value().as_object()); |
128 | 0 | position = deserialized_record.position; |
129 | | |
130 | | // 2. Set value’s point 2 to the sub-deserialization of serialized.[[P2]]. |
131 | 0 | deserialized_record = TRY(HTML::structured_deserialize_internal(vm(), serialized, realm, memory, position)); |
132 | 0 | if (deserialized_record.value.has_value() && is<DOMPoint>(deserialized_record.value.value().as_object())) |
133 | 0 | m_p2 = dynamic_cast<DOMPoint&>(deserialized_record.value.release_value().as_object()); |
134 | 0 | position = deserialized_record.position; |
135 | | |
136 | | // 3. Set value’s point 3 to the sub-deserialization of serialized.[[P3]]. |
137 | 0 | deserialized_record = TRY(HTML::structured_deserialize_internal(vm(), serialized, realm, memory, position)); |
138 | 0 | if (deserialized_record.value.has_value() && is<DOMPoint>(deserialized_record.value.value().as_object())) |
139 | 0 | m_p3 = dynamic_cast<DOMPoint&>(deserialized_record.value.release_value().as_object()); |
140 | 0 | position = deserialized_record.position; |
141 | | |
142 | | // 4. Set value’s point 4 to the sub-deserialization of serialized.[[P4]]. |
143 | 0 | deserialized_record = TRY(HTML::structured_deserialize_internal(vm(), serialized, realm, memory, position)); |
144 | 0 | if (deserialized_record.value.has_value() && is<DOMPoint>(deserialized_record.value.value().as_object())) |
145 | 0 | m_p4 = dynamic_cast<DOMPoint&>(deserialized_record.value.release_value().as_object()); |
146 | 0 | position = deserialized_record.position; |
147 | |
|
148 | 0 | return {}; |
149 | 0 | } |
150 | | |
151 | | void DOMQuad::initialize(JS::Realm& realm) |
152 | 0 | { |
153 | 0 | Base::initialize(realm); |
154 | 0 | WEB_SET_PROTOTYPE_FOR_INTERFACE(DOMQuad); |
155 | 0 | } |
156 | | |
157 | | void DOMQuad::visit_edges(Cell::Visitor& visitor) |
158 | 0 | { |
159 | 0 | Base::visit_edges(visitor); |
160 | 0 | visitor.visit(m_p1); |
161 | 0 | visitor.visit(m_p2); |
162 | 0 | visitor.visit(m_p3); |
163 | 0 | visitor.visit(m_p4); |
164 | 0 | } |
165 | | |
166 | | } |