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;
26use crate::script_runtime::CanGc;
27
28#[dom_struct]
30pub(crate) struct DOMPointReadOnly {
31 reflector_: Reflector,
32 x: Cell<f64>,
33 y: Cell<f64>,
34 z: Cell<f64>,
35 w: Cell<f64>,
36}
37
38impl DOMPointReadOnly {
39 pub(crate) fn new_inherited(x: f64, y: f64, z: f64, w: f64) -> DOMPointReadOnly {
40 DOMPointReadOnly {
41 x: Cell::new(x),
42 y: Cell::new(y),
43 z: Cell::new(z),
44 w: Cell::new(w),
45 reflector_: Reflector::new(),
46 }
47 }
48
49 pub(crate) fn new(
50 cx: &mut JSContext,
51 global: &GlobalScope,
52 x: f64,
53 y: f64,
54 z: f64,
55 w: f64,
56 ) -> DomRoot<DOMPointReadOnly> {
57 Self::new_with_proto(cx, global, None, x, y, z, w)
58 }
59
60 fn new_with_proto(
61 cx: &mut JSContext,
62 global: &GlobalScope,
63 proto: Option<HandleObject>,
64 x: f64,
65 y: f64,
66 z: f64,
67 w: f64,
68 ) -> DomRoot<DOMPointReadOnly> {
69 reflect_dom_object_with_proto_and_cx(
70 Box::new(DOMPointReadOnly::new_inherited(x, y, z, w)),
71 global,
72 proto,
73 cx,
74 )
75 }
76}
77
78impl DOMPointReadOnlyMethods<crate::DomTypeHolder> for DOMPointReadOnly {
79 fn Constructor(
81 cx: &mut JSContext,
82 global: &GlobalScope,
83 proto: Option<HandleObject>,
84 x: f64,
85 y: f64,
86 z: f64,
87 w: f64,
88 ) -> Fallible<DomRoot<DOMPointReadOnly>> {
89 Ok(DOMPointReadOnly::new_with_proto(
90 cx, global, proto, x, y, z, w,
91 ))
92 }
93
94 fn FromPoint(cx: &mut JSContext, global: &GlobalScope, init: &DOMPointInit) -> DomRoot<Self> {
96 Self::new(cx, global, init.x, init.y, init.z, init.w)
97 }
98
99 fn X(&self) -> f64 {
101 self.x.get()
102 }
103
104 fn Y(&self) -> f64 {
106 self.y.get()
107 }
108
109 fn Z(&self) -> f64 {
111 self.z.get()
112 }
113
114 fn W(&self) -> f64 {
116 self.w.get()
117 }
118
119 fn MatrixTransform(
122 &self,
123 cx: &mut JSContext,
124 matrix: &DOMMatrixInit,
125 ) -> Fallible<DomRoot<DOMPoint>> {
126 let matrix_object = match dommatrixinit_to_matrix(matrix) {
128 Ok(converted) => converted,
129 Err(exception) => {
130 return Err(exception);
131 },
132 };
133 let x = self.X();
135 let y = self.Y();
136 let z = self.Z();
137 let w = self.W();
138 let m = &matrix_object.1;
140 let transformed_point = DOMPointInit {
141 x: m.m11 * x + m.m21 * y + m.m31 * z + m.m41 * w,
142 y: m.m12 * x + m.m22 * y + m.m32 * z + m.m42 * w,
143 z: m.m13 * x + m.m23 * y + m.m33 * z + m.m43 * w,
144 w: m.m14 * x + m.m24 * y + m.m34 * z + m.m44 * w,
145 };
146 Ok(DOMPoint::new_from_init(
149 cx,
150 &self.global(),
151 &transformed_point,
152 ))
153 }
154}
155
156#[expect(non_snake_case)]
157pub(crate) trait DOMPointWriteMethods {
158 fn SetX(&self, value: f64);
159 fn SetY(&self, value: f64);
160 fn SetZ(&self, value: f64);
161 fn SetW(&self, value: f64);
162}
163
164impl DOMPointWriteMethods for DOMPointReadOnly {
165 fn SetX(&self, value: f64) {
166 self.x.set(value);
167 }
168
169 fn SetY(&self, value: f64) {
170 self.y.set(value);
171 }
172
173 fn SetZ(&self, value: f64) {
174 self.z.set(value);
175 }
176
177 fn SetW(&self, value: f64) {
178 self.w.set(value);
179 }
180}
181
182impl Serializable for DOMPointReadOnly {
183 type Index = DomPointIndex;
184 type Data = DomPoint;
185
186 fn serialize(&self) -> Result<(DomPointId, Self::Data), ()> {
187 let serialized = DomPoint {
188 x: self.x.get(),
189 y: self.y.get(),
190 z: self.z.get(),
191 w: self.w.get(),
192 };
193 Ok((DomPointId::new(), serialized))
194 }
195
196 #[expect(unsafe_code)]
197 fn deserialize(
198 owner: &GlobalScope,
199 serialized: Self::Data,
200 _can_gc: CanGc,
201 ) -> Result<DomRoot<Self>, ()> {
202 let mut cx = unsafe { script_bindings::script_runtime::temp_cx() };
204 Ok(Self::new(
205 &mut cx,
206 owner,
207 serialized.x,
208 serialized.y,
209 serialized.z,
210 serialized.w,
211 ))
212 }
213
214 fn serialized_storage<'a>(
215 data: StructuredData<'a, '_>,
216 ) -> &'a mut Option<FxHashMap<DomPointId, Self::Data>> {
217 match data {
218 StructuredData::Reader(r) => &mut r.points,
219 StructuredData::Writer(w) => &mut w.points,
220 }
221 }
222}