Skip to main content

script/dom/geometry/
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, 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    /// <https://drafts.csswg.org/geometry/#dom-domrectreadonly-domrectreadonly>
94    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    // https://drafts.csswg.org/geometry/#dom-domrectreadonly-fromrect
107    #[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    /// <https://drafts.csswg.org/geometry/#dom-domrectreadonly-x>
119    fn X(&self) -> f64 {
120        self.x.get()
121    }
122
123    /// <https://drafts.csswg.org/geometry/#dom-domrectreadonly-y>
124    fn Y(&self) -> f64 {
125        self.y.get()
126    }
127
128    /// <https://drafts.csswg.org/geometry/#dom-domrectreadonly-width>
129    fn Width(&self) -> f64 {
130        self.width.get()
131    }
132
133    /// <https://drafts.csswg.org/geometry/#dom-domrectreadonly-height>
134    fn Height(&self) -> f64 {
135        self.height.get()
136    }
137
138    /// <https://drafts.csswg.org/geometry/#dom-domrectreadonly-top>
139    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    /// <https://drafts.csswg.org/geometry/#dom-domrectreadonly-right>
149    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    /// <https://drafts.csswg.org/geometry/#dom-domrectreadonly-bottom>
159    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    /// <https://drafts.csswg.org/geometry/#dom-domrectreadonly-left>
169    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
179/// <https://drafts.csswg.org/geometry/#ref-for-create-a-domrectreadonly-from-the-dictionary>
180pub(super) fn create_a_domrectreadonly_from_the_dictionary(other: &DOMRectInit) -> DOMRectReadOnly {
181    // NOTE: We trivially combine all three steps into one
182
183    // Step 1. Let rect be a new DOMRectReadOnly or DOMRect as appropriate.
184
185    // Step 2. Set rect’s variables x coordinate to other’s x dictionary member, y coordinate to other’s y
186    // dictionary member, width dimension to other’s width dictionary member and height dimension to
187    // other’s height dictionary member.
188
189    // Step 3. Return rect.
190
191    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}