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;
24
25#[dom_struct]
27pub(crate) struct DOMQuad {
28 reflector_: Reflector,
29 p1: Dom<DOMPoint>,
30 p2: Dom<DOMPoint>,
31 p3: Dom<DOMPoint>,
32 p4: Dom<DOMPoint>,
33}
34
35impl DOMQuad {
36 fn new_inherited(p1: &DOMPoint, p2: &DOMPoint, p3: &DOMPoint, p4: &DOMPoint) -> DOMQuad {
37 DOMQuad {
38 reflector_: Reflector::new(),
39 p1: Dom::from_ref(p1),
40 p2: Dom::from_ref(p2),
41 p3: Dom::from_ref(p3),
42 p4: Dom::from_ref(p4),
43 }
44 }
45
46 pub(crate) fn new(
47 cx: &mut JSContext,
48 global: &GlobalScope,
49 p1: &DOMPoint,
50 p2: &DOMPoint,
51 p3: &DOMPoint,
52 p4: &DOMPoint,
53 ) -> DomRoot<DOMQuad> {
54 Self::new_with_proto(cx, global, None, p1, p2, p3, p4)
55 }
56
57 fn new_with_proto(
58 cx: &mut JSContext,
59 global: &GlobalScope,
60 proto: Option<HandleObject>,
61 p1: &DOMPoint,
62 p2: &DOMPoint,
63 p3: &DOMPoint,
64 p4: &DOMPoint,
65 ) -> DomRoot<DOMQuad> {
66 reflect_dom_object_with_proto_and_cx(
67 Box::new(DOMQuad::new_inherited(p1, p2, p3, p4)),
68 global,
69 proto,
70 cx,
71 )
72 }
73}
74
75impl DOMQuadMethods<crate::DomTypeHolder> for DOMQuad {
76 fn Constructor(
78 cx: &mut JSContext,
79 global: &GlobalScope,
80 proto: Option<HandleObject>,
81 p1: &DOMPointInit,
82 p2: &DOMPointInit,
83 p3: &DOMPointInit,
84 p4: &DOMPointInit,
85 ) -> Fallible<DomRoot<DOMQuad>> {
86 let p1 = DOMPoint::new_from_init(cx, global, p1);
87 let p2 = DOMPoint::new_from_init(cx, global, p2);
88 let p3 = DOMPoint::new_from_init(cx, global, p3);
89 let p4 = DOMPoint::new_from_init(cx, global, p4);
90 Ok(DOMQuad::new_with_proto(
91 cx, global, proto, &p1, &p2, &p3, &p4,
92 ))
93 }
94
95 fn FromRect(cx: &mut JSContext, global: &GlobalScope, other: &DOMRectInit) -> DomRoot<DOMQuad> {
97 let p1 = DOMPoint::new(cx, global, other.x, other.y, 0f64, 1f64);
98 let p2 = DOMPoint::new(cx, global, other.x + other.width, other.y, 0f64, 1f64);
99 let p3 = DOMPoint::new(
100 cx,
101 global,
102 other.x + other.width,
103 other.y + other.height,
104 0f64,
105 1f64,
106 );
107 let p4 = DOMPoint::new(cx, global, other.x, other.y + other.height, 0f64, 1f64);
108 DOMQuad::new(cx, global, &p1, &p2, &p3, &p4)
109 }
110
111 fn FromQuad(cx: &mut JSContext, global: &GlobalScope, other: &DOMQuadInit) -> DomRoot<DOMQuad> {
113 let p1 = DOMPoint::new_from_init(cx, global, &other.p1);
114 let p2 = DOMPoint::new_from_init(cx, global, &other.p2);
115 let p3 = DOMPoint::new_from_init(cx, global, &other.p3);
116 let p4 = DOMPoint::new_from_init(cx, global, &other.p4);
117 DOMQuad::new(cx, global, &p1, &p2, &p3, &p4)
118 }
119
120 fn P1(&self) -> DomRoot<DOMPoint> {
122 DomRoot::from_ref(&self.p1)
123 }
124
125 fn P2(&self) -> DomRoot<DOMPoint> {
127 DomRoot::from_ref(&self.p2)
128 }
129
130 fn P3(&self) -> DomRoot<DOMPoint> {
132 DomRoot::from_ref(&self.p3)
133 }
134
135 fn P4(&self) -> DomRoot<DOMPoint> {
137 DomRoot::from_ref(&self.p4)
138 }
139
140 fn GetBounds(&self, cx: &mut JSContext) -> DomRoot<DOMRect> {
142 let nan_safe_minimum = |a: f64, b: f64| {
144 if a.is_nan() || b.is_nan() {
145 f64::NAN
146 } else {
147 a.min(b)
148 }
149 };
150
151 let nan_safe_maximum = |a: f64, b: f64| {
153 if a.is_nan() || b.is_nan() {
154 f64::NAN
155 } else {
156 a.max(b)
157 }
158 };
159
160 let left = nan_safe_minimum(
166 nan_safe_minimum(self.p1.X(), self.p2.X()),
167 nan_safe_minimum(self.p3.X(), self.p4.X()),
168 );
169
170 let top = nan_safe_minimum(
173 nan_safe_minimum(self.p1.Y(), self.p2.Y()),
174 nan_safe_minimum(self.p3.Y(), self.p4.Y()),
175 );
176
177 let right = nan_safe_maximum(
180 nan_safe_maximum(self.p1.X(), self.p2.X()),
181 nan_safe_maximum(self.p3.X(), self.p4.X()),
182 );
183
184 let bottom = nan_safe_maximum(
187 nan_safe_maximum(self.p1.Y(), self.p2.Y()),
188 nan_safe_maximum(self.p3.Y(), self.p4.Y()),
189 );
190
191 DOMRect::new(cx, &self.global(), left, top, right - left, bottom - top)
195 }
196}
197
198impl Serializable for DOMQuad {
199 type Index = DomQuadIndex;
200 type Data = DomQuad;
201
202 fn serialize(&self) -> Result<(DomQuadId, Self::Data), ()> {
203 let make_point = |src: DomRoot<DOMPoint>| -> DomPoint {
204 DomPoint {
205 x: src.X(),
206 y: src.Y(),
207 z: src.Z(),
208 w: src.W(),
209 }
210 };
211 let serialized = DomQuad {
212 p1: make_point(self.P1()),
213 p2: make_point(self.P2()),
214 p3: make_point(self.P3()),
215 p4: make_point(self.P4()),
216 };
217 Ok((DomQuadId::new(), serialized))
218 }
219
220 fn deserialize(
221 cx: &mut JSContext,
222 owner: &GlobalScope,
223 serialized: Self::Data,
224 ) -> Result<DomRoot<Self>, ()>
225 where
226 Self: Sized,
227 {
228 let p1 = DOMPoint::new(
229 cx,
230 owner,
231 serialized.p1.x,
232 serialized.p1.y,
233 serialized.p1.z,
234 serialized.p1.w,
235 );
236 let p2 = DOMPoint::new(
237 cx,
238 owner,
239 serialized.p2.x,
240 serialized.p2.y,
241 serialized.p2.z,
242 serialized.p2.w,
243 );
244 let p3 = DOMPoint::new(
245 cx,
246 owner,
247 serialized.p3.x,
248 serialized.p3.y,
249 serialized.p3.z,
250 serialized.p3.w,
251 );
252 let p4 = DOMPoint::new(
253 cx,
254 owner,
255 serialized.p4.x,
256 serialized.p4.y,
257 serialized.p4.z,
258 serialized.p4.w,
259 );
260 Ok(Self::new(cx, owner, &p1, &p2, &p3, &p4))
261 }
262
263 fn serialized_storage<'a>(
264 data: StructuredData<'a, '_>,
265 ) -> &'a mut Option<FxHashMap<DomQuadId, Self::Data>> {
266 match data {
267 StructuredData::Reader(reader) => &mut reader.quads,
268 StructuredData::Writer(writer) => &mut writer.quads,
269 }
270 }
271}