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