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