script/dom/animations/
documenttimeline.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 dom_struct::dom_struct;
6use js::gc::HandleObject;
7use num_traits::ToPrimitive;
8use script_bindings::codegen::GenericBindings::DocumentTimelineBinding::DocumentTimelineOptions;
9use script_bindings::root::DomRoot;
10use script_bindings::script_runtime::CanGc;
11use servo_base::cross_process_instant::CrossProcessInstant;
12use servo_config::pref;
13use time::Duration;
14
15use crate::dom::bindings::codegen::Bindings::DocumentTimelineBinding::DocumentTimelineMethods;
16use crate::dom::bindings::reflector::{reflect_dom_object, reflect_dom_object_with_proto};
17use crate::dom::types::{AnimationTimeline, Window};
18
19/// <https://drafts.csswg.org/web-animations-1/#the-documenttimeline-interface>
20#[dom_struct]
21pub(crate) struct DocumentTimeline {
22    animation_timeline: AnimationTimeline,
23    /// An offset from the `Document`'s time origin as a [`Duration`] offset. This is determined by the original
24    /// "originTime" specified during construction of the [`AnimationTimeline`] in the options object.
25    /// Note that this value might be negative.
26    ///
27    /// See:
28    ///   - <https://drafts.csswg.org/web-animations-1/#dom-documenttimelineoptions-origintime>
29    ///   - <https://html.spec.whatwg.org/multipage/#concept-settings-object-time-origin>
30    #[no_trace]
31    origin_offset: Duration,
32}
33
34impl DocumentTimeline {
35    pub(crate) fn new_with_duration(
36        window: &Window,
37        proto: Option<HandleObject>,
38        origin_time: Duration,
39        can_gc: CanGc,
40    ) -> DomRoot<Self> {
41        let duration_since_time_origin =
42            CrossProcessInstant::now() - window.navigation_start() - origin_time;
43        reflect_dom_object_with_proto(
44            Box::new(Self {
45                animation_timeline: AnimationTimeline::new_inherited(duration_since_time_origin),
46                origin_offset: origin_time,
47            }),
48            window,
49            proto,
50            can_gc,
51        )
52    }
53
54    pub(crate) fn new(window: &Window, can_gc: CanGc) -> DomRoot<DocumentTimeline> {
55        let duration = if pref!(layout_animations_test_enabled) {
56            Duration::ZERO
57        } else {
58            CrossProcessInstant::now() - window.navigation_start()
59        };
60        reflect_dom_object(
61            Box::new(Self {
62                animation_timeline: AnimationTimeline::new_inherited(duration),
63                origin_offset: Duration::ZERO,
64            }),
65            window,
66            can_gc,
67        )
68    }
69
70    /// Updates the value of the `AnimationTimeline` to the current clock time.
71    pub(crate) fn update(&self, window: &Window) {
72        let duration_since_time_origin =
73            CrossProcessInstant::now() - window.navigation_start() - self.origin_offset;
74        self.animation_timeline
75            .set_current_time(duration_since_time_origin);
76    }
77
78    /// Increments the current value of the timeline by a specific number of seconds.
79    /// This is used for testing.
80    pub(crate) fn advance_specific(&self, by: Duration) {
81        self.animation_timeline.advance_specific(by);
82    }
83}
84
85impl DocumentTimelineMethods<crate::DomTypeHolder> for DocumentTimeline {
86    fn Constructor(
87        window: &Window,
88        proto: Option<HandleObject>,
89        can_gc: CanGc,
90        options: &DocumentTimelineOptions,
91    ) -> DomRoot<Self> {
92        Self::new_with_duration(
93            window,
94            proto,
95            Duration::seconds_f64(options.originTime.to_f64().unwrap_or_default() / 1000.),
96            can_gc,
97        )
98    }
99}