1use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use js::context::JSContext;
9use js::rust::HandleObject;
10use rustc_hash::FxHashMap;
11use servo_base::id::{DomRectId, DomRectIndex};
12use servo_constellation_traits::DomRect;
13
14use crate::dom::bindings::codegen::Bindings::DOMRectReadOnlyBinding::{
15 DOMRectInit, DOMRectReadOnlyMethods,
16};
17use crate::dom::bindings::error::Fallible;
18use crate::dom::bindings::reflector::{
19 Reflector, reflect_dom_object_with_cx, reflect_dom_object_with_proto,
20};
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 global: &GlobalScope,
49 proto: Option<HandleObject>,
50 x: f64,
51 y: f64,
52 width: f64,
53 height: f64,
54 can_gc: CanGc,
55 ) -> DomRoot<DOMRectReadOnly> {
56 reflect_dom_object_with_proto(
57 Box::new(DOMRectReadOnly::new_inherited(x, y, width, height)),
58 global,
59 proto,
60 can_gc,
61 )
62 }
63
64 pub(crate) fn new_from_dictionary(
65 global: &GlobalScope,
66 proto: Option<HandleObject>,
67 dictionary: &DOMRectInit,
68 can_gc: CanGc,
69 ) -> DomRoot<DOMRectReadOnly> {
70 reflect_dom_object_with_proto(
71 Box::new(create_a_domrectreadonly_from_the_dictionary(dictionary)),
72 global,
73 proto,
74 can_gc,
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 global: &GlobalScope,
99 proto: Option<HandleObject>,
100 can_gc: CanGc,
101 x: f64,
102 y: f64,
103 width: f64,
104 height: f64,
105 ) -> Fallible<DomRoot<DOMRectReadOnly>> {
106 Ok(DOMRectReadOnly::new(
107 global, proto, x, y, width, height, can_gc,
108 ))
109 }
110
111 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
113 fn FromRect(
114 cx: &mut JSContext,
115 global: &GlobalScope,
116 other: &DOMRectInit,
117 ) -> DomRoot<DOMRectReadOnly> {
118 let dom_rect = create_a_domrectreadonly_from_the_dictionary(other);
119
120 reflect_dom_object_with_cx(Box::new(dom_rect), global, cx)
121 }
122
123 fn X(&self) -> f64 {
125 self.x.get()
126 }
127
128 fn Y(&self) -> f64 {
130 self.y.get()
131 }
132
133 fn Width(&self) -> f64 {
135 self.width.get()
136 }
137
138 fn Height(&self) -> f64 {
140 self.height.get()
141 }
142
143 fn Top(&self) -> f64 {
145 let height = self.height.get();
146 if height >= 0f64 {
147 self.y.get()
148 } else {
149 self.y.get() + height
150 }
151 }
152
153 fn Right(&self) -> f64 {
155 let width = self.width.get();
156 if width < 0f64 {
157 self.x.get()
158 } else {
159 self.x.get() + width
160 }
161 }
162
163 fn Bottom(&self) -> f64 {
165 let height = self.height.get();
166 if height < 0f64 {
167 self.y.get()
168 } else {
169 self.y.get() + height
170 }
171 }
172
173 fn Left(&self) -> f64 {
175 let width = self.width.get();
176 if width >= 0f64 {
177 self.x.get()
178 } else {
179 self.x.get() + width
180 }
181 }
182}
183
184pub(super) fn create_a_domrectreadonly_from_the_dictionary(other: &DOMRectInit) -> DOMRectReadOnly {
186 DOMRectReadOnly {
197 reflector_: Reflector::new(),
198 x: Cell::new(other.x),
199 y: Cell::new(other.y),
200 width: Cell::new(other.width),
201 height: Cell::new(other.height),
202 }
203}
204
205type Type = DomRectId;
206
207impl Serializable for DOMRectReadOnly {
208 type Index = DomRectIndex;
209 type Data = DomRect;
210
211 fn serialize(&self) -> Result<(DomRectId, Self::Data), ()> {
212 let serialized = DomRect {
213 x: self.X(),
214 y: self.Y(),
215 width: self.Width(),
216 height: self.Height(),
217 };
218 Ok((DomRectId::new(), serialized))
219 }
220
221 fn deserialize(
222 owner: &GlobalScope,
223 serialized: Self::Data,
224 can_gc: CanGc,
225 ) -> Result<DomRoot<Self>, ()>
226 where
227 Self: Sized,
228 {
229 Ok(Self::new(
230 owner,
231 None,
232 serialized.x,
233 serialized.y,
234 serialized.width,
235 serialized.height,
236 can_gc,
237 ))
238 }
239
240 fn serialized_storage<'a>(
241 data: StructuredData<'a, '_>,
242 ) -> &'a mut Option<FxHashMap<Type, Self::Data>> {
243 match data {
244 StructuredData::Reader(reader) => &mut reader.rects,
245 StructuredData::Writer(writer) => &mut writer.rects,
246 }
247 }
248}