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