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