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
qwasmcompositor.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
5#include "qwasmwindow.h"
6
7#include <private/qeventdispatcher_wasm_p.h>
8#include <private/qwasmsuspendresumecontrol_p.h>
9
10#include <qpa/qwindowsysteminterface.h>
11
12#include <emscripten/html5.h>
13
14using namespace emscripten;
15
16bool QWasmCompositor::m_requestUpdateHoldEnabled = false;
17
18QWasmCompositor::QWasmCompositor(QWasmScreen *screen)
19: QObject(screen)
20, m_animationFrameHandler(QWasmAnimationFrameHandler([this](double frametime){
21 Q_UNUSED(frametime);
22 this->m_requestAnimationFrameId = -1;
23 this->deliverUpdateRequests();
24 }))
25{
26 QWindowSystemInterface::setSynchronousWindowSystemEvents(true);
27}
28
30{
31 if (m_requestAnimationFrameId != -1)
32 m_animationFrameHandler.cancelAnimationFrame(m_requestAnimationFrameId);
33
34 // TODO(mikolaj.boc): Investigate if m_isEnabled is needed at all. It seems like a frame should
35 // not be generated after this instead.
36 m_isEnabled = false; // prevent frame() from creating a new m_context
37}
38
40 QWasmWindow *window)
41{
42 auto allWindows = screen()->allWindows();
43 setEnabled(std::any_of(allWindows.begin(), allWindows.end(), [](QWasmWindow *element) {
44 return !element->context2d().isUndefined();
45 }));
46 if (changeType == QWasmWindowTreeNodeChangeType::NodeRemoval)
47 m_requestUpdateWindows.remove(window);
48}
49
50void QWasmCompositor::setEnabled(bool enabled)
51{
52 m_isEnabled = enabled;
53}
54
55// requestUpdate delivery is initially disabled at startup, while Qt completes
56// startup tasks such as font loading. This function enables requestUpdate delivery
57// again.
59{
60 const bool wasEnabled = m_requestUpdateHoldEnabled;
61 m_requestUpdateHoldEnabled = false;
62 return wasEnabled;
63}
64
65void QWasmCompositor::requestUpdateWindow(QWasmWindow *window, const QRect &updateRect, UpdateRequestDeliveryType updateType)
66{
67 auto it = m_requestUpdateWindows.find(window);
68 if (it == m_requestUpdateWindows.end()) {
69 m_requestUpdateWindows.insert(window, std::make_tuple(updateRect, updateType));
70 } else {
71 // Already registered, but upgrade ExposeEventDeliveryType to UpdateRequestDeliveryType.
72 // if needed, to make sure QWindow::updateRequest's are matched.
73 if (std::get<0>(it.value()) != updateRect) {
74 QRegion region;
75 region |= std::get<0>(it.value());
76 region |= updateRect;
77 std::get<0>(it.value()) = region.boundingRect();
78 }
79 if (std::get<1>(it.value()) == ExposeEventDelivery &&
80 updateType == UpdateRequestDelivery)
81 std::get<1>(it.value()) = UpdateRequestDelivery;
82 }
83
85}
86
87// Requests an update/new frame using RequestAnimationFrame
89{
90 if (m_requestAnimationFrameId != -1)
91 return;
92
93 if (m_requestUpdateHoldEnabled)
94 return;
95
96 m_requestAnimationFrameId = m_animationFrameHandler.requestAnimationFrame();
97}
98
99void QWasmCompositor::deliverUpdateRequests()
100{
101 // We may get new update requests during the window content update below:
102 // prepare for recording the new update set by setting aside the current
103 // update set.
104 auto requestUpdateWindows = m_requestUpdateWindows;
105 m_requestUpdateWindows.clear();
106
107 // Update window content, either all windows or a spesific set of windows. Use the correct
108 // update type: QWindow subclasses expect that requested and delivered updateRequests matches
109 // exactly.
110 m_inDeliverUpdateRequest = true;
111 for (auto it = requestUpdateWindows.constBegin(); it != requestUpdateWindows.constEnd(); ++it) {
112 auto *window = it.key();
113
114 const QRect updateRect = std::get<0>(it.value());
115 const UpdateRequestDeliveryType updateType = std::get<1>(it.value());
116 deliverUpdateRequest(window, updateRect, updateType);
117 }
118
119 m_inDeliverUpdateRequest = false;
120 frame(requestUpdateWindows.keys());
121}
122
123void QWasmCompositor::deliverUpdateRequest(
124 QWasmWindow *window,
125 const QRect &updateRect,
126 UpdateRequestDeliveryType updateType)
127{
128 QWindow *qwindow = window->window();
129
130 // Make sure the DPR value for the window is up to date on expose/repaint.
131 // FIXME: listen to native DPR change events instead, if/when available.
132 QWindowSystemInterface::handleWindowDevicePixelRatioChanged(qwindow);
133
134 // Update by deliverUpdateRequest and expose event according to requested update
135 // type. If the window has not yet been exposed then we must expose it first regardless
136 // of update type. The deliverUpdateRequest must still be sent in this case in order
137 // to maintain correct window update state.
138 if (updateType == UpdateRequestDelivery) {
139 if (qwindow->isExposed() == false)
140 QWindowSystemInterface::handleExposeEvent(qwindow, updateRect);
141 window->deliverUpdateRequest();
142 } else {
143 QWindowSystemInterface::handleExposeEvent(qwindow, updateRect);
144 }
145}
146
147void QWasmCompositor::handleBackingStoreFlush(QWindow *window, const QRect &updateRect)
148{
149 // Request update to flush the updated backing store content, unless we are currently
150 // processing an update, in which case the new content will flushed as a part of that update.
151 if (!m_inDeliverUpdateRequest)
152 requestUpdateWindow(static_cast<QWasmWindow *>(window->handle()), updateRect);
153}
154
155void QWasmCompositor::frame(const QList<QWasmWindow *> &windows)
156{
157 if (!m_isEnabled || !screen())
158 return;
159
160 for (QWasmWindow *window : windows)
161 window->paint();
162}
163
165{
166 return static_cast<QWasmScreen *>(parent());
167}
168
169QWasmAnimationFrameHandler::QWasmAnimationFrameHandler(std::function<void(double)> handler)
170{
171 auto argCastWrapper = [handler](val arg){ handler(arg.as<double>()); };
172 m_handlerIndex = QWasmSuspendResumeControl::get()->registerEventHandler(argCastWrapper);
173}
174
176{
177 QWasmSuspendResumeControl::get()->removeEventHandler(m_handlerIndex);
178}
179
181{
182 using ReturnType = double; // FIXME emscripten::val::call() does not support int64_t
183 val handler = QWasmSuspendResumeControl::get()->jsEventHandlerAt(m_handlerIndex);
184 return int64_t(val::global("window").call<ReturnType>("requestAnimationFrame", handler));
185}
186
188{
189 val::global("window").call<void>("cancelAnimationFrame", double(id));
190}
void cancelAnimationFrame(int64_t id)
void onWindowTreeChanged(QWasmWindowTreeNodeChangeType changeType, QWasmWindow *window)
static bool releaseRequestUpdateHold()
void setEnabled(bool enabled)
QWasmScreen * screen()
QWasmCompositor(QWasmScreen *screen)
friend class QWasmCompositor
QWasmWindowTreeNodeChangeType