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