1use dom_struct::dom_struct;
6use js::context::JSContext;
7use js::rust::HandleObject;
8use rustc_hash::FxHashMap;
9use script_bindings::reflector::{Reflector, reflect_dom_object_with_proto_and_cx};
10use servo_base::id::{DomQuadId, DomQuadIndex};
11use servo_constellation_traits::{DomPoint, DomQuad};
12
13use crate::dom::bindings::codegen::Bindings::DOMPointBinding::{DOMPointInit, DOMPointMethods};
14use crate::dom::bindings::codegen::Bindings::DOMQuadBinding::{DOMQuadInit, DOMQuadMethods};
15use crate::dom::bindings::codegen::Bindings::DOMRectReadOnlyBinding::DOMRectInit;
16use crate::dom::bindings::error::Fallible;
17use crate::dom::bindings::reflector::DomGlobal;
18use crate::dom::bindings::root::{Dom, DomRoot};
19use crate::dom::bindings::serializable::Serializable;
20use crate::dom::bindings::structuredclone::StructuredData;
21use crate::dom::dompoint::DOMPoint;
22use crate::dom::domrect::DOMRect;
23use crate::dom::globalscope::GlobalScope;
24use crate::script_runtime::CanGc;
25
26#[dom_struct]
28pub(crate) struct DOMQuad {
29 reflector_: Reflector,
30 p1: Dom<DOMPoint>,
31 p2: Dom<DOMPoint>,
32 p3: Dom<DOMPoint>,
33 p4: Dom<DOMPoint>,
34}
35
36impl DOMQuad {
37 fn new_inherited(p1: &DOMPoint, p2: &DOMPoint, p3: &DOMPoint, p4: &DOMPoint) -> DOMQuad {
38 DOMQuad {
39 reflector_: Reflector::new(),
40 p1: Dom::from_ref(p1),
41 p2: Dom::from_ref(p2),
42 p3: Dom::from_ref(p3),
43 p4: Dom::from_ref(p4),
44 }
45 }
46
47 pub(crate) fn new(
48 cx: &mut JSContext,
49 global: &GlobalScope,
50 p1: &DOMPoint,
51 p2: &DOMPoint,
52 p3: &DOMPoint,
53 p4: &DOMPoint,
54 ) -> DomRoot<DOMQuad> {
55 Self::new_with_proto(cx, global, None, p1, p2, p3, p4)
56 }
57
58 fn new_with_proto(
59 cx: &mut JSContext,
60 global: &GlobalScope,
61 proto: Option<HandleObject>,
62 p1: &DOMPoint,
63 p2: &DOMPoint,
64 p3: &DOMPoint,
65 p4: &DOMPoint,
66 ) -> DomRoot<DOMQuad> {
67 reflect_dom_object_with_proto_and_cx(
68 Box::new(DOMQuad::new_inherited(p1, p2, p3, p4)),
69 global,
70 proto,
71 cx,
72 )
73 }
74}
75
76impl DOMQuadMethods<crate::DomTypeHolder> for DOMQuad {
77 fn Constructor(
79 cx: &mut JSContext,
80 global: &GlobalScope,
81 proto: Option<HandleObject>,
82 p1: &DOMPointInit,
83 p2: &DOMPointInit,
84 p3: &DOMPointInit,
85 p4: &DOMPointInit,
86 ) -> Fallible<DomRoot<DOMQuad>> {
87 let p1 = DOMPoint::new_from_init(cx, global, p1);
88 let p2 = DOMPoint::new_from_init(cx, global, p2);
89 let p3 = DOMPoint::new_from_init(cx, global, p3);
90 let p4 = DOMPoint::new_from_init(cx, global, p4);
91 Ok(DOMQuad::new_with_proto(
92 cx, global, proto, &p1, &p2, &p3, &p4,
93 ))
94 }
95
96 fn FromRect(cx: &mut JSContext, global: &GlobalScope, other: &DOMRectInit) -> DomRoot<DOMQuad> {
98 let p1 = DOMPoint::new(cx, global, other.x, other.y, 0f64, 1f64);
99 let p2 = DOMPoint::new(cx, global, other.x + other.width, other.y, 0f64, 1f64);
100 let p3 = DOMPoint::new(
101 cx,
102 global,
103 other.x + other.width,
104 other.y + other.height,
105 0f64,
106 1f64,
107 );
108 let p4 = DOMPoint::new(cx, global, other.x, other.y + other.height, 0f64, 1f64);
109 DOMQuad::new(cx, global, &p1, &p2, &p3, &p4)
110 }
111
112 fn FromQuad(cx: &mut JSContext, global: &GlobalScope, other: &DOMQuadInit) -> DomRoot<DOMQuad> {
114 let p1 = DOMPoint::new_from_init(cx, global, &other.p1);
115 let p2 = DOMPoint::new_from_init(cx, global, &other.p2);
116 let p3 = DOMPoint::new_from_init(cx, global, &other.p3);
117 let p4 = DOMPoint::new_from_init(cx, global, &other.p4);
118 DOMQuad::new(cx, global, &p1, &p2, &p3, &p4)
119 }
120
121 fn P1(&self) -> DomRoot<DOMPoint> {
123 DomRoot::from_ref(&self.p1)
124 }
125
126 fn P2(&self) -> DomRoot<DOMPoint> {
128 DomRoot::from_ref(&self.p2)
129 }
130
131 fn P3(&self) -> DomRoot<DOMPoint> {
133 DomRoot::from_ref(&self.p3)
134 }
135
136 fn P4(&self) -> DomRoot<DOMPoint> {
138 DomRoot::from_ref(&self.p4)
139 }
140
141 fn GetBounds(&self, cx: &mut JSContext) -> DomRoot<DOMRect> {
143 let nan_safe_minimum = |a: f64, b: f64| {
145 if a.is_nan() || b.is_nan() {
146 f64::NAN
147 } else {
148 a.min(b)
149 }
150 };
151
152 let nan_safe_maximum = |a: f64, b: f64| {
154 if a.is_nan() || b.is_nan() {
155 f64::NAN
156 } else {
157 a.max(b)
158 }
159 };
160
161 let left = nan_safe_minimum(
167 nan_safe_minimum(self.p1.X(), self.p2.X()),
168 nan_safe_minimum(self.p3.X(), self.p4.X()),
169 );
170
171 let top = nan_safe_minimum(
174 nan_safe_minimum(self.p1.Y(), self.p2.Y()),
175 nan_safe_minimum(self.p3.Y(), self.p4.Y()),
176 );
177
178 let right = nan_safe_maximum(
181 nan_safe_maximum(self.p1.X(), self.p2.X()),
182 nan_safe_maximum(self.p3.X(), self.p4.X()),
183 );
184
185 let bottom = nan_safe_maximum(
188 nan_safe_maximum(self.p1.Y(), self.p2.Y()),
189 nan_safe_maximum(self.p3.Y(), self.p4.Y()),
190 );
191
192 DOMRect::new(
196 &self.global(),
197 left,
198 top,
199 right - left,
200 bottom - top,
201 CanGc::from_cx(cx),
202 )
203 }
204}
205
206impl Serializable for DOMQuad {
207 type Index = DomQuadIndex;
208 type Data = DomQuad;
209
210 fn serialize(&self) -> Result<(DomQuadId, Self::Data), ()> {
211 let make_point = |src: DomRoot<DOMPoint>| -> DomPoint {
212 DomPoint {
213 x: src.X(),
214 y: src.Y(),
215 z: src.Z(),
216 w: src.W(),
217 }
218 };
219 let serialized = DomQuad {
220 p1: make_point(self.P1()),
221 p2: make_point(self.P2()),
222 p3: make_point(self.P3()),
223 p4: make_point(self.P4()),
224 };
225 Ok((DomQuadId::new(), serialized))
226 }
227
228 #[expect(unsafe_code)]
229 fn deserialize(
230 owner: &GlobalScope,
231 serialized: Self::Data,
232 _can_gc: CanGc,
233 ) -> Result<DomRoot<Self>, ()>
234 where
235 Self: Sized,
236 {
237 let mut cx = unsafe { script_bindings::script_runtime::temp_cx() };
239 let p1 = DOMPoint::new(
240 &mut cx,
241 owner,
242 serialized.p1.x,
243 serialized.p1.y,
244 serialized.p1.z,
245 serialized.p1.w,
246 );
247 let p2 = DOMPoint::new(
248 &mut cx,
249 owner,
250 serialized.p2.x,
251 serialized.p2.y,
252 serialized.p2.z,
253 serialized.p2.w,
254 );
255 let p3 = DOMPoint::new(
256 &mut cx,
257 owner,
258 serialized.p3.x,
259 serialized.p3.y,
260 serialized.p3.z,
261 serialized.p3.w,
262 );
263 let p4 = DOMPoint::new(
264 &mut cx,
265 owner,
266 serialized.p4.x,
267 serialized.p4.y,
268 serialized.p4.z,
269 serialized.p4.w,
270 );
271 Ok(Self::new(&mut cx, owner, &p1, &p2, &p3, &p4))
272 }
273
274 fn serialized_storage<'a>(
275 data: StructuredData<'a, '_>,
276 ) -> &'a mut Option<FxHashMap<DomQuadId, Self::Data>> {
277 match data {
278 StructuredData::Reader(reader) => &mut reader.quads,
279 StructuredData::Writer(writer) => &mut writer.quads,
280 }
281 }
282}