Ver código fonte

LibWeb: Ensure all DocumentTimeline objects have the same time value

The DocumentTimeline constructor used the current millisecond time to
initialize its currentTime, but that means that a newly created timeline
would always have a different time value than other timelines that have
been through the update_animations_and_send_events function.
Matthew Olsson 1 ano atrás
pai
commit
37322baf54

+ 3 - 0
Tests/LibWeb/Text/expected/WebAnimations/misc/DocumentTimeline.txt

@@ -0,0 +1,3 @@
+new timeline time equals document timeline time: true
+new timeline originTime defaults to 0: true
+new timeline originTime offsets from document timeline: true

+ 18 - 0
Tests/LibWeb/Text/input/WebAnimations/misc/DocumentTimeline.html

@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<script src="../../include.js"></script>
+<script>
+    test(() => {
+        function timesAreClose(a, b) {
+            return Math.abs(a - b) <= 1;
+        }
+        let timeline = new DocumentTimeline();
+        println(`new timeline time equals document timeline time: ${timesAreClose(timeline.currentTime, document.timeline.currentTime)}`);
+
+        timeline = new DocumentTimeline({ originTime: 0 });
+        println(`new timeline originTime defaults to 0: ${timesAreClose(timeline.currentTime, document.timeline.currentTime)}`);
+
+        timeline = new DocumentTimeline({ originTime: 1000 });
+        let passed = timesAreClose(timeline.currentTime + 1000, document.timeline.currentTime);
+        println(`new timeline originTime offsets from document timeline: ${passed}`)
+    });
+</script>

+ 8 - 3
Userland/Libraries/LibWeb/Animations/DocumentTimeline.cpp

@@ -20,9 +20,14 @@ JS_DEFINE_ALLOCATOR(DocumentTimeline);
 JS::NonnullGCPtr<DocumentTimeline> DocumentTimeline::create(JS::Realm& realm, DOM::Document& document, HighResolutionTime::DOMHighResTimeStamp origin_time)
 {
     auto timeline = realm.heap().allocate<DocumentTimeline>(realm, realm, document, origin_time);
-    auto* window_or_worker = dynamic_cast<HTML::WindowOrWorkerGlobalScopeMixin*>(&realm.global_object());
-    VERIFY(window_or_worker);
-    timeline->set_current_time(window_or_worker->performance()->now());
+    auto current_time = document.last_animation_frame_timestamp();
+    if (!current_time.has_value()) {
+        // The document hasn't processed an animation frame yet, so just use the exact current time
+        auto* window_or_worker = dynamic_cast<HTML::WindowOrWorkerGlobalScopeMixin*>(&realm.global_object());
+        VERIFY(window_or_worker);
+        current_time = window_or_worker->performance()->now();
+    }
+    timeline->set_current_time(current_time);
     return timeline;
 }
 

+ 1 - 0
Userland/Libraries/LibWeb/DOM/Document.cpp

@@ -4233,6 +4233,7 @@ void Document::update_animations_and_send_events(Optional<double> const& timesta
     // - Running the update an animation’s finished state procedure for any animations whose current time has been
     //   updated.
     // - Queueing animation events for any such animations.
+    m_last_animation_frame_timestamp = timestamp;
     for (auto const& timeline : m_associated_animation_timelines)
         timeline->set_current_time(timestamp);
 

+ 2 - 0
Userland/Libraries/LibWeb/DOM/Document.h

@@ -596,6 +596,7 @@ public:
     void restore_the_history_object_state(JS::NonnullGCPtr<HTML::SessionHistoryEntry> entry);
 
     JS::NonnullGCPtr<Animations::DocumentTimeline> timeline();
+    auto const& last_animation_frame_timestamp() const { return m_last_animation_frame_timestamp; }
 
     void associate_with_timeline(JS::NonnullGCPtr<Animations::AnimationTimeline>);
     void disassociate_with_timeline(JS::NonnullGCPtr<Animations::AnimationTimeline>);
@@ -889,6 +890,7 @@ private:
 
     // https://www.w3.org/TR/web-animations-1/#document-default-document-timeline
     JS::GCPtr<Animations::DocumentTimeline> m_default_timeline;
+    Optional<double> m_last_animation_frame_timestamp;
 
     // https://www.w3.org/TR/web-animations-1/#pending-animation-event-queue
     Vector<PendingAnimationEvent> m_pending_animation_event_queue;