1use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use js::context::JSContext;
9use js::rust::HandleObject;
10use rustc_hash::FxHashMap;
11use script_bindings::reflector::{Reflector, reflect_dom_object_with_proto_and_cx};
12use servo_base::id::{DomPointId, DomPointIndex};
13use servo_constellation_traits::DomPoint;
14
15use crate::dom::bindings::codegen::Bindings::DOMMatrixBinding::DOMMatrixInit;
16use crate::dom::bindings::codegen::Bindings::DOMPointBinding::DOMPointInit;
17use crate::dom::bindings::codegen::Bindings::DOMPointReadOnlyBinding::DOMPointReadOnlyMethods;
18use crate::dom::bindings::error::Fallible;
19use crate::dom::bindings::reflector::DomGlobal;
20use crate::dom::bindings::root::DomRoot;
21use crate::dom::bindings::serializable::Serializable;
22use crate::dom::bindings::structuredclone::StructuredData;
23use crate::dom::dommatrixreadonly::dommatrixinit_to_matrix;
24use crate::dom::globalscope::GlobalScope;
25use crate::dom::types::DOMPoint;
26
27#[dom_struct]
29pub(crate) struct DOMPointReadOnly {
30 reflector_: Reflector,
31 x: Cell<f64>,
32 y: Cell<f64>,
33 z: Cell<f64>,
34 w: Cell<f64>,
35}
36
37impl DOMPointReadOnly {
38 pub(crate) fn new_inherited(x: f64, y: f64, z: f64, w: f64) -> DOMPointReadOnly {
39 DOMPointReadOnly {
40 x: Cell::new(x),
41 y: Cell::new(y),
42 z: Cell::new(z),
43 w: Cell::new(w),
44 reflector_: Reflector::new(),
45 }
46 }
47
48 pub(crate) fn new(
49 cx: &mut JSContext,
50 global: &GlobalScope,
51 x: f64,
52 y: f64,
53 z: f64,
54 w: f64,
55 ) -> DomRoot<DOMPointReadOnly> {
56 Self::new_with_proto(cx, global, None, x, y, z, w)
57 }
58
59 fn new_with_proto(
60 cx: &mut JSContext,
61 global: &GlobalScope,
62 proto: Option<HandleObject>,
63 x: f64,
64 y: f64,
65 z: f64,
66 w: f64,
67 ) -> DomRoot<DOMPointReadOnly> {
68 reflect_dom_object_with_proto_and_cx(
69 Box::new(DOMPointReadOnly::new_inherited(x, y, z, w)),
70 global,
71 proto,
72 cx,
73 )
74 }
75}
76
77impl DOMPointReadOnlyMethods<crate::DomTypeHolder> for DOMPointReadOnly {
78 fn Constructor(
80 cx: &mut JSContext,
81 global: &GlobalScope,
82 proto: Option<HandleObject>,
83 x: f64,
84 y: f64,
85 z: f64,
86 w: f64,
87 ) -> Fallible<DomRoot<DOMPointReadOnly>> {
88 Ok(DOMPointReadOnly::new_with_proto(
89 cx, global, proto, x, y, z, w,
90 ))
91 }
92
93 fn FromPoint(cx: &mut JSContext, global: &GlobalScope, init: &DOMPointInit) -> DomRoot<Self> {
95 Self::new(cx, global, init.x, init.y, init.z, init.w)
96 }
97
98 fn X(&self) -> f64 {
100 self.x.get()
101 }
102
103 fn Y(&self) -> f64 {
105 self.y.get()
106 }
107
108 fn Z(&self) -> f64 {
110 self.z.get()
111 }
112
113 fn W(&self) -> f64 {
115 self.w.get()
116 }
117
118 fn MatrixTransform(
121 &self,
122 cx: &mut JSContext,
123 matrix: &DOMMatrixInit,
124 ) -> Fallible<DomRoot<DOMPoint>> {
125 let matrix_object = match dommatrixinit_to_matrix(matrix) {
127 Ok(converted) => converted,
128 Err(exception) => {
129 return Err(exception);
130 },
131 };
132 let x = self.X();
134 let y = self.Y();
135 let z = self.Z();
136 let w = self.W();
137 let m = &matrix_object.1;
139 let transformed_point = DOMPointInit {
140 x: m.m11 * x + m.m21 * y + m.m31 * z + m.m41 * w,
141 y: m.m12 * x + m.m22 * y + m.m32 * z + m.m42 * w,
142 z: m.m13 * x + m.m23 * y + m.m33 * z + m.m43 * w,
143 w: m.m14 * x + m.m24 * y + m.m34 * z + m.m44 * w,
144 };
145 Ok(DOMPoint::new_from_init(
148 cx,
149 &self.global(),
150 &transformed_point,
151 ))
152 }
153}
154
155#[expect(non_snake_case)]
156pub(crate) trait DOMPointWriteMethods {
157 fn SetX(&self, value: f64);
158 fn SetY(&self, value: f64);
159 fn SetZ(&self, value: f64);
160 fn SetW(&self, value: f64);
161}
162
163impl DOMPointWriteMethods for DOMPointReadOnly {
164 fn SetX(&self, value: f64) {
165 self.x.set(value);
166 }
167
168 fn SetY(&self, value: f64) {
169 self.y.set(value);
170 }
171
172 fn SetZ(&self, value: f64) {
173 self.z.set(value);
174 }
175
176 fn SetW(&self, value: f64) {
177 self.w.set(value);
178 }
179}
180
181impl Serializable for DOMPointReadOnly {
182 type Index = DomPointIndex;
183 type Data = DomPoint;
184
185 fn serialize(&self) -> Result<(DomPointId, Self::Data), ()> {
186 let serialized = DomPoint {
187 x: self.x.get(),
188 y: self.y.get(),
189 z: self.z.get(),
190 w: self.w.get(),
191 };
192 Ok((DomPointId::new(), serialized))
193 }
194
195 fn deserialize(
196 cx: &mut JSContext,
197 owner: &GlobalScope,
198 serialized: Self::Data,
199 ) -> Result<DomRoot<Self>, ()> {
200 Ok(Self::new(
201 cx,
202 owner,
203 serialized.x,
204 serialized.y,
205 serialized.z,
206 serialized.w,
207 ))
208 }
209
210 fn serialized_storage<'a>(
211 data: StructuredData<'a, '_>,
212 ) -> &'a mut Option<FxHashMap<DomPointId, Self::Data>> {
213 match data {
214 StructuredData::Reader(r) => &mut r.points,
215 StructuredData::Writer(w) => &mut w.points,
216 }
217 }
218}