Skip to main content

script/dom/
domrectreadonly.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use 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    /// <https://drafts.fxtf.org/geometry/#dom-domrectreadonly-domrectreadonly>
97    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    // https://drafts.fxtf.org/geometry/#dom-domrectreadonly-fromrect
112    #[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    /// <https://drafts.fxtf.org/geometry/#dom-domrectreadonly-x>
124    fn X(&self) -> f64 {
125        self.x.get()
126    }
127
128    /// <https://drafts.fxtf.org/geometry/#dom-domrectreadonly-y>
129    fn Y(&self) -> f64 {
130        self.y.get()
131    }
132
133    /// <https://drafts.fxtf.org/geometry/#dom-domrectreadonly-width>
134    fn Width(&self) -> f64 {
135        self.width.get()
136    }
137
138    /// <https://drafts.fxtf.org/geometry/#dom-domrectreadonly-height>
139    fn Height(&self) -> f64 {
140        self.height.get()
141    }
142
143    /// <https://drafts.fxtf.org/geometry/#dom-domrectreadonly-top>
144    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    /// <https://drafts.fxtf.org/geometry/#dom-domrectreadonly-right>
154    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    /// <https://drafts.fxtf.org/geometry/#dom-domrectreadonly-bottom>
164    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    /// <https://drafts.fxtf.org/geometry/#dom-domrectreadonly-left>
174    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
184/// <https://drafts.fxtf.org/geometry/#ref-for-create-a-domrectreadonly-from-the-dictionary>
185pub(super) fn create_a_domrectreadonly_from_the_dictionary(other: &DOMRectInit) -> DOMRectReadOnly {
186    // NOTE: We trivially combine all three steps into one
187
188    // Step 1. Let rect be a new DOMRectReadOnly or DOMRect as appropriate.
189
190    // Step 2. Set rect’s variables x coordinate to other’s x dictionary member, y coordinate to other’s y
191    // dictionary member, width dimension to other’s width dictionary member and height dimension to
192    // other’s height dictionary member.
193
194    // Step 3. Return rect.
195
196    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}