Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwasmanimationdriver.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6
7#include <emscripten/val.h>
8
9QT_BEGIN_NAMESPACE
10
11
12// QWasmAnimationDriver drives animations using requestAnimationFrame(). This
13// ensures that animations are advanced in sync with frame update calls, which
14// again are synced to the screen refresh rate.
15
16namespace {
17 constexpr int FallbackTimerInterval = 500;
18}
19
20QWasmAnimationDriver::QWasmAnimationDriver(QUnifiedTimer *)
21 : QAnimationDriver(nullptr)
22{
23 connect(this, &QAnimationDriver::started, this, &QWasmAnimationDriver::start);
24 connect(this, &QAnimationDriver::stopped, this, &QWasmAnimationDriver::stop);
25}
26
27QWasmAnimationDriver::~QWasmAnimationDriver()
28{
29 disconnect(this, &QAnimationDriver::started, this, &QWasmAnimationDriver::start);
30 disconnect(this, &QAnimationDriver::stopped, this, &QWasmAnimationDriver::stop);
31
32 if (m_animateCallbackHandle != 0)
33 QWasmAnimationFrameMultiHandler::instance()->unregisterAnimateCallback(m_animateCallbackHandle);
34}
35
36qint64 QWasmAnimationDriver::elapsed() const
37{
38 return isRunning() ? qint64(m_currentTimestamp - m_startTimestamp) : 0;
39}
40
41double QWasmAnimationDriver::getCurrentTimeFromTimeline() const
42{
43 // Get the current timeline time, which is an equivalent time source to the
44 // animation frame time source. According to the documentation this API
45 // may be unavailable in various cases; check for null before accessing.
46 emscripten::val document = emscripten::val::global("document");
47 emscripten::val timeline = document["timeline"];
48 if (!timeline.isNull() && !timeline.isUndefined()) {
49 emscripten::val currentTime = timeline["currentTime"];
50 if (!currentTime.isNull() && !currentTime.isUndefined())
51 return currentTime.as<double>();
52 }
53 return 0;
54}
55
56void QWasmAnimationDriver::handleFallbackTimeout()
57{
58 if (!isRunning())
59 return;
60
61 // Get the current time from a timing source equivalent to the animation frame time
62 double currentTime = getCurrentTimeFromTimeline();
63 if (currentTime == 0)
64 currentTime = m_currentTimestamp + FallbackTimerInterval;
65 const double timeSinceLastFrame = currentTime - m_currentTimestamp;
66
67 // Advance animations if animations are active but there has been no rcent animation
68 // frame callback.
69 if (timeSinceLastFrame > FallbackTimerInterval * 0.8) {
70 m_currentTimestamp = currentTime;
71 advance();
72 }
73}
74
75void QWasmAnimationDriver::start()
76{
77 if (isRunning())
78 return;
79
80 // Set start timestamp to document.timeline.currentTime()
81 m_startTimestamp = getCurrentTimeFromTimeline();
82 m_currentTimestamp = m_startTimestamp;
83
84 // Register animate callback
85 m_animateCallbackHandle = QWasmAnimationFrameMultiHandler::instance()->registerAnimateCallback(
86 [this](double timestamp) { handleAnimationFrame(timestamp); });
87
88 // Start fallback timer to ensure animations advance even if animaton frame callbacks stop coming
89 fallbackTimer.setInterval(FallbackTimerInterval);
90 connect(&fallbackTimer, &QTimer::timeout, this, &QWasmAnimationDriver::handleFallbackTimeout);
91 fallbackTimer.start();
92
93 QAnimationDriver::start();
94}
95
96void QWasmAnimationDriver::stop()
97{
98 m_startTimestamp = 0;
99 m_currentTimestamp = 0;
100
101 // Stop and disconnect the fallback timer
102 fallbackTimer.stop();
103 disconnect(&fallbackTimer, &QTimer::timeout, this, &QWasmAnimationDriver::handleFallbackTimeout);
104
105 // Deregister the animation frame callback
106 if (m_animateCallbackHandle != 0) {
107 QWasmAnimationFrameMultiHandler::instance()->unregisterAnimateCallback(m_animateCallbackHandle);
108 m_animateCallbackHandle = 0;
109 }
110
111 QAnimationDriver::stop();
112}
113
114void QWasmAnimationDriver::handleAnimationFrame(double timestamp)
115{
116 if (!isRunning())
117 return;
118
119 m_currentTimestamp = timestamp;
120
121 // Fall back to setting m_startTimestamp here in cases where currentTime
122 // was not available in start() (gives 0 elapsed time for the first frame)
123 if (m_startTimestamp == 0)
124 m_startTimestamp = timestamp;
125
126 advance();
127}
128
129QT_END_NAMESPACE
constexpr int FallbackTimerInterval