Skip to main content

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