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::{
12 Reflector, reflect_dom_object_with_cx, reflect_dom_object_with_proto_and_cx,
13};
14use servo_base::id::{DomRectId, DomRectIndex};
15use servo_constellation_traits::DomRect;
16
17use crate::dom::bindings::codegen::Bindings::DOMRectReadOnlyBinding::{
18 DOMRectInit, DOMRectReadOnlyMethods,
19};
20use crate::dom::bindings::error::Fallible;
21use crate::dom::bindings::root::DomRoot;
22use crate::dom::bindings::serializable::Serializable;
23use crate::dom::bindings::structuredclone::StructuredData;
24use crate::dom::globalscope::GlobalScope;
25use crate::script_runtime::CanGc;
26
27#[dom_struct]
28pub(crate) struct DOMRectReadOnly {
29 reflector_: Reflector,
30 x: Cell<f64>,
31 y: Cell<f64>,
32 width: Cell<f64>,
33 height: Cell<f64>,
34}
35
36impl DOMRectReadOnly {
37 pub(crate) fn new_inherited(x: f64, y: f64, width: f64, height: f64) -> DOMRectReadOnly {
38 DOMRectReadOnly {
39 x: Cell::new(x),
40 y: Cell::new(y),
41 width: Cell::new(width),
42 height: Cell::new(height),
43 reflector_: Reflector::new(),
44 }
45 }
46
47 pub(crate) fn new(
48 cx: &mut JSContext,
49 global: &GlobalScope,
50 proto: Option<HandleObject>,
51 x: f64,
52 y: f64,
53 width: f64,
54 height: f64,
55 ) -> DomRoot<DOMRectReadOnly> {
56 reflect_dom_object_with_proto_and_cx(
57 Box::new(DOMRectReadOnly::new_inherited(x, y, width, height)),
58 global,
59 proto,
60 cx,
61 )
62 }
63
64 pub(crate) fn new_from_dictionary(
65 cx: &mut JSContext,
66 global: &GlobalScope,
67 proto: Option<HandleObject>,
68 dictionary: &DOMRectInit,
69 ) -> DomRoot<DOMRectReadOnly> {
70 reflect_dom_object_with_proto_and_cx(
71 Box::new(create_a_domrectreadonly_from_the_dictionary(dictionary)),
72 global,
73 proto,
74 cx,
75 )
76 }
77
78 pub(crate) fn set_x(&self, value: f64) {
79 self.x.set(value);
80 }
81
82 pub(crate) fn set_y(&self, value: f64) {
83 self.y.set(value);
84 }
85
86 pub(crate) fn set_width(&self, value: f64) {
87 self.width.set(value);
88 }
89
90 pub(crate) fn set_height(&self, value: f64) {
91 self.height.set(value);
92 }
93}
94
95impl DOMRectReadOnlyMethods<crate::DomTypeHolder> for DOMRectReadOnly {
96 fn Constructor(
98 cx: &mut JSContext,
99 global: &GlobalScope,
100 proto: Option<HandleObject>,
101 x: f64,
102 y: f64,
103 width: f64,
104 height: f64,
105 ) -> Fallible<DomRoot<DOMRectReadOnly>> {
106 Ok(DOMRectReadOnly::new(cx, global, proto, x, y, width, height))
107 }
108
109 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
111 fn FromRect(
112 cx: &mut JSContext,
113 global: &GlobalScope,
114 other: &DOMRectInit,
115 ) -> DomRoot<DOMRectReadOnly> {
116 let dom_rect = create_a_domrectreadonly_from_the_dictionary(other);
117
118 reflect_dom_object_with_cx(Box::new(dom_rect), global, cx)
119 }
120
121 fn X(&self) -> f64 {
123 self.x.get()
124 }
125
126 fn Y(&self) -> f64 {
128 self.y.get()
129 }
130
131 fn Width(&self) -> f64 {
133 self.width.get()
134 }
135
136 fn Height(&self) -> f64 {
138 self.height.get()
139 }
140
141 fn Top(&self) -> f64 {
143 let height = self.height.get();
144 if height >= 0f64 {
145 self.y.get()
146 } else {
147 self.y.get() + height
148 }
149 }
150
151 fn Right(&self) -> f64 {
153 let width = self.width.get();
154 if width < 0f64 {
155 self.x.get()
156 } else {
157 self.x.get() + width
158 }
159 }
160
161 fn Bottom(&self) -> f64 {
163 let height = self.height.get();
164 if height < 0f64 {
165 self.y.get()
166 } else {
167 self.y.get() + height
168 }
169 }
170
171 fn Left(&self) -> f64 {
173 let width = self.width.get();
174 if width >= 0f64 {
175 self.x.get()
176 } else {
177 self.x.get() + width
178 }
179 }
180}
181
182pub(super) fn create_a_domrectreadonly_from_the_dictionary(other: &DOMRectInit) -> DOMRectReadOnly {
184 DOMRectReadOnly {
195 reflector_: Reflector::new(),
196 x: Cell::new(other.x),
197 y: Cell::new(other.y),
198 width: Cell::new(other.width),
199 height: Cell::new(other.height),
200 }
201}
202
203type Type = DomRectId;
204
205impl Serializable for DOMRectReadOnly {
206 type Index = DomRectIndex;
207 type Data = DomRect;
208
209 fn serialize(&self) -> Result<(DomRectId, Self::Data), ()> {
210 let serialized = DomRect {
211 x: self.X(),
212 y: self.Y(),
213 width: self.Width(),
214 height: self.Height(),
215 };
216 Ok((DomRectId::new(), serialized))
217 }
218
219 #[expect(unsafe_code)]
220 fn deserialize(
221 owner: &GlobalScope,
222 serialized: Self::Data,
223 _can_gc: CanGc,
224 ) -> Result<DomRoot<Self>, ()>
225 where
226 Self: Sized,
227 {
228 let mut cx = unsafe { script_bindings::script_runtime::temp_cx() };
230 Ok(Self::new(
231 &mut cx,
232 owner,
233 None,
234 serialized.x,
235 serialized.y,
236 serialized.width,
237 serialized.height,
238 ))
239 }
240
241 fn serialized_storage<'a>(
242 data: StructuredData<'a, '_>,
243 ) -> &'a mut Option<FxHashMap<Type, Self::Data>> {
244 match data {
245 StructuredData::Reader(reader) => &mut reader.rects,
246 StructuredData::Writer(writer) => &mut writer.rects,
247 }
248 }
249}