script/dom/
intersectionobserverentry.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::rust::HandleObject;
9
10use super::bindings::codegen::Bindings::IntersectionObserverEntryBinding::{
11    IntersectionObserverEntryInit, IntersectionObserverEntryMethods,
12};
13use super::bindings::num::Finite;
14use crate::dom::bindings::codegen::Bindings::DOMRectReadOnlyBinding::DOMRectInit;
15use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto};
16use crate::dom::bindings::root::{Dom, DomRoot};
17use crate::dom::domrectreadonly::DOMRectReadOnly;
18use crate::dom::element::Element;
19use crate::dom::window::Window;
20use crate::script_runtime::CanGc;
21
22/// An individual IntersectionObserver entry.
23///
24/// <https://w3c.github.io/IntersectionObserver/#intersection-observer-entry>
25#[dom_struct]
26pub(crate) struct IntersectionObserverEntry {
27    reflector_: Reflector,
28    // <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserverentry-time>
29    time: Cell<Finite<f64>>,
30    // <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserverentry-rootbounds>
31    root_bounds: Option<Dom<DOMRectReadOnly>>,
32    // <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserverentry-boundingclientrect>
33    bounding_client_rect: Dom<DOMRectReadOnly>,
34    // <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserverentry-intersectionrect>
35    intersection_rect: Dom<DOMRectReadOnly>,
36    // <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserverentry-isintersecting>
37    is_intersecting: Cell<bool>,
38    // <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserverentry-isvisible>
39    is_visible: Cell<bool>,
40    // <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserverentry-intersectionratio>
41    intersection_ratio: Cell<Finite<f64>>,
42    // <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserverentry-target>
43    target: Dom<Element>,
44}
45
46impl IntersectionObserverEntry {
47    #[allow(clippy::too_many_arguments)]
48    fn new_inherited(
49        time: Finite<f64>,
50        root_bounds: Option<&DOMRectReadOnly>,
51        bounding_client_rect: &DOMRectReadOnly,
52        intersection_rect: &DOMRectReadOnly,
53        is_intersecting: bool,
54        is_visible: bool,
55        intersection_ratio: Finite<f64>,
56        target: &Element,
57    ) -> Self {
58        Self {
59            reflector_: Reflector::new(),
60            target: Dom::from_ref(target),
61            time: Cell::new(time),
62            root_bounds: root_bounds.map(Dom::from_ref),
63            bounding_client_rect: Dom::from_ref(bounding_client_rect),
64            intersection_rect: Dom::from_ref(intersection_rect),
65            is_intersecting: Cell::new(is_intersecting),
66            is_visible: Cell::new(is_visible),
67            intersection_ratio: Cell::new(intersection_ratio),
68        }
69    }
70
71    #[allow(clippy::too_many_arguments)]
72    pub(crate) fn new(
73        window: &Window,
74        proto: Option<HandleObject>,
75        time: Finite<f64>,
76        root_bounds: Option<&DOMRectReadOnly>,
77        bounding_client_rect: &DOMRectReadOnly,
78        intersection_rect: &DOMRectReadOnly,
79        is_intersecting: bool,
80        is_visible: bool,
81        intersection_ratio: Finite<f64>,
82        target: &Element,
83        can_gc: CanGc,
84    ) -> DomRoot<Self> {
85        let observer = Box::new(Self::new_inherited(
86            time,
87            root_bounds,
88            bounding_client_rect,
89            intersection_rect,
90            is_intersecting,
91            is_visible,
92            intersection_ratio,
93            target,
94        ));
95        reflect_dom_object_with_proto(observer, window, proto, can_gc)
96    }
97
98    fn new_from_dictionary(
99        window: &Window,
100        proto: Option<HandleObject>,
101        init: &IntersectionObserverEntryInit,
102        can_gc: CanGc,
103    ) -> DomRoot<Self> {
104        let domrectreadonly_from_dictionary = |dictionary: &DOMRectInit| {
105            DOMRectReadOnly::new_from_dictionary(
106                window.as_global_scope(),
107                proto,
108                dictionary,
109                can_gc,
110            )
111        };
112        let observer = Box::new(Self::new_inherited(
113            init.time,
114            Some(&*domrectreadonly_from_dictionary(&init.rootBounds)),
115            &domrectreadonly_from_dictionary(&init.boundingClientRect),
116            &domrectreadonly_from_dictionary(&init.intersectionRect),
117            init.isIntersecting,
118            init.isVisible,
119            init.intersectionRatio,
120            &init.target,
121        ));
122        reflect_dom_object_with_proto(observer, window, proto, can_gc)
123    }
124}
125
126impl IntersectionObserverEntryMethods<crate::DomTypeHolder> for IntersectionObserverEntry {
127    /// > The attribute must return a DOMHighResTimeStamp that corresponds to the time the
128    /// > intersection was recorded, relative to the time origin of the global object
129    /// > associated with the IntersectionObserver instance that generated the notification.
130    ///
131    /// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserverentry-time>
132    fn Time(&self) -> Finite<f64> {
133        self.time.get()
134    }
135
136    /// > For a same-origin-domain target, this will be the root intersection rectangle.
137    /// > Otherwise, this will be null. Note that if the target is in a different browsing
138    /// > context than the intersection root, this will be in a different coordinate system
139    /// > than boundingClientRect and intersectionRect.
140    ///
141    /// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserverentry-rootbounds>
142    fn GetRootBounds(&self) -> Option<DomRoot<DOMRectReadOnly>> {
143        self.root_bounds.as_ref().map(|rect| rect.as_rooted())
144    }
145
146    /// > A DOMRectReadOnly obtained by getting the bounding box for target.
147    ///
148    /// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserverentry-boundingclientrect>
149    fn BoundingClientRect(&self) -> DomRoot<DOMRectReadOnly> {
150        self.bounding_client_rect.as_rooted()
151    }
152
153    /// > boundingClientRect, intersected by each of target's ancestors' clip rects (up to
154    /// > but not including root), intersected with the root intersection rectangle. This
155    /// > value represents the portion of target that intersects with the root intersection
156    /// > rectangle.
157    ///
158    /// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserverentry-intersectionrect>
159    fn IntersectionRect(&self) -> DomRoot<DOMRectReadOnly> {
160        self.intersection_rect.as_rooted()
161    }
162
163    /// > True if the target intersects with the root; false otherwise. This flag makes it
164    /// > possible to distinguish between an IntersectionObserverEntry signalling the
165    /// > transition from intersecting to not-intersecting; and an IntersectionObserverEntry
166    /// > signalling a transition from not-intersecting to intersecting with a zero-area
167    /// > intersection rect (as will happen with edge-adjacent intersections, or when the
168    /// > boundingClientRect has zero area).
169    ///
170    /// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserverentry-isintersecting>
171    fn IsIntersecting(&self) -> bool {
172        self.is_intersecting.get()
173    }
174
175    /// > Contains the result of running the visibility algorithm on target.
176    ///
177    /// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserverentry-isvisible>
178    fn IsVisible(&self) -> bool {
179        self.is_visible.get()
180    }
181
182    /// > If the boundingClientRect has non-zero area, this will be the ratio of
183    /// > intersectionRect area to boundingClientRect area. Otherwise, this will be 1 if the
184    /// > isIntersecting is true, and 0 if not.
185    ///
186    /// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserverentry-intersectionratio>
187    fn IntersectionRatio(&self) -> Finite<f64> {
188        self.intersection_ratio.get()
189    }
190
191    /// > The Element whose intersection with the intersection root changed.
192    ///
193    /// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserverentry-target>
194    fn Target(&self) -> DomRoot<Element> {
195        self.target.as_rooted()
196    }
197
198    /// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserverentry-intersectionobserverentry>
199    fn Constructor(
200        window: &Window,
201        proto: Option<HandleObject>,
202        can_gc: CanGc,
203        init: &IntersectionObserverEntryInit,
204    ) -> DomRoot<IntersectionObserverEntry> {
205        Self::new_from_dictionary(window, proto, init, can_gc)
206    }
207}