summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.json5
-rw-r--r--configure.pri11
-rw-r--r--examples/widgets/widgets/tablet/tabletcanvas.cpp6
-rw-r--r--mkspecs/features/toolchain.prf4
-rw-r--r--mkspecs/features/uikit/default_pre.prf2
-rw-r--r--mkspecs/features/wasm/qt.prf12
-rw-r--r--mkspecs/features/wasm/wasm.prf81
-rw-r--r--mkspecs/wasm-emscripten/qmake.conf90
-rw-r--r--mkspecs/wasm-emscripten/qplatformdefs.h181
-rw-r--r--qmake/generators/makefile.cpp13
-rw-r--r--qmake/generators/unix/unixmake2.cpp7
-rw-r--r--qmake/generators/win32/mingw_make.cpp2
-rw-r--r--qmake/generators/win32/winmakefile.cpp3
-rw-r--r--src/3rdparty/double-conversion/include/double-conversion/utils.h2
-rw-r--r--src/3rdparty/tinycbor/src/cborinternal_p.h69
-rw-r--r--src/3rdparty/tinycbor/src/compilersupport_p.h59
-rw-r--r--src/3rdparty/wasm/DejaVuSans.ttfbin0 -> 493564 bytes
-rw-r--r--src/3rdparty/wasm/LICENSE15
-rw-r--r--src/3rdparty/wasm/Vera.ttfbin0 -> 65932 bytes
-rw-r--r--src/3rdparty/wasm/qt_attribution.json21
-rw-r--r--src/corelib/codecs/qtextcodec_p.h2
-rw-r--r--src/corelib/configure.json4
-rw-r--r--src/corelib/global/archdetect.cpp2
-rw-r--r--src/corelib/global/qcompilerdetection.h3
-rw-r--r--src/corelib/global/qlogging.cpp40
-rw-r--r--src/corelib/global/qoperatingsystemversion_win.cpp2
-rw-r--r--src/corelib/global/qprocessordetection.h6
-rw-r--r--src/corelib/global/qsystemdetection.h2
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp36
-rw-r--r--src/corelib/io/qfilesystemengine_win.cpp16
-rw-r--r--src/corelib/io/qsettings.cpp11
-rw-r--r--src/corelib/io/qsettings_win.cpp28
-rw-r--r--src/corelib/kernel/qcore_mac_p.h79
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp22
-rw-r--r--src/corelib/kernel/qeventdispatcher_unix.cpp2
-rw-r--r--src/corelib/kernel/qeventdispatcher_win.cpp12
-rw-r--r--src/corelib/kernel/qeventloop.cpp24
-rw-r--r--src/corelib/kernel/qmetaobject_p.h4
-rw-r--r--src/corelib/kernel/qmetaobjectbuilder_p.h7
-rw-r--r--src/corelib/kernel/qmetatype.cpp191
-rw-r--r--src/corelib/kernel/qmetatype.h33
-rw-r--r--src/corelib/kernel/qmetatype_p.h12
-rw-r--r--src/corelib/kernel/qsharedmemory_win.cpp9
-rw-r--r--src/corelib/kernel/qsystemsemaphore_win.cpp7
-rw-r--r--src/corelib/mimetypes/qmimedatabase.cpp2
-rw-r--r--src/corelib/plugin/plugin.pri1
-rw-r--r--src/corelib/plugin/qfactoryloader.cpp91
-rw-r--r--src/corelib/plugin/qfactoryloader_p.h3
-rw-r--r--src/corelib/plugin/qlibrary.cpp44
-rw-r--r--src/corelib/plugin/qlibrary_win.cpp4
-rw-r--r--src/corelib/plugin/qplugin.h15
-rw-r--r--src/corelib/plugin/qplugin_p.h75
-rw-r--r--src/corelib/plugin/qpluginloader.cpp11
-rw-r--r--src/corelib/plugin/qsystemlibrary.cpp2
-rw-r--r--src/corelib/thread/qthread_win.cpp10
-rw-r--r--src/corelib/tools/qlocale_win.cpp2
-rw-r--r--src/corelib/tools/qsimd.cpp17
-rw-r--r--src/corelib/tools/qtimezoneprivate_win.cpp18
-rw-r--r--src/corelib/tools/qunicodetables_p.h6
-rw-r--r--src/corelib/tools/tools.pri2
-rw-r--r--src/gui/configure.json10
-rw-r--r--src/gui/configure.pri1
-rw-r--r--src/gui/kernel/qguiapplication.cpp12
-rw-r--r--src/gui/kernel/qopenglcontext.cpp3
-rw-r--r--src/gui/kernel/qwindowsysteminterface_p.h2
-rw-r--r--src/gui/opengl/qopenglframebufferobject.cpp45
-rw-r--r--src/gui/painting/qimagescale.cpp5
-rw-r--r--src/gui/text/qfontengine.cpp2
-rw-r--r--src/network/access/access.pri7
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp13
-rw-r--r--src/network/access/qnetworkaccessmanager.h3
-rw-r--r--src/network/access/qnetworkreplywasmimpl.cpp640
-rw-r--r--src/network/access/qnetworkreplywasmimpl_p.h153
-rw-r--r--src/network/configure.json3
-rw-r--r--src/network/kernel/qhostinfo_win.cpp8
-rw-r--r--src/network/kernel/qnetworkinterface_win.cpp21
-rw-r--r--src/network/kernel/qnetworkproxy_win.cpp11
-rw-r--r--src/network/socket/qlocalserver_win.cpp10
-rw-r--r--src/network/socket/qlocalsocket_win.cpp6
-rw-r--r--src/network/socket/qnativesocketengine_win.cpp7
-rw-r--r--src/opengl/qglframebufferobject.cpp22
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp6
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp7
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplication.mm6
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm12
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.mm5
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm46
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm8
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.mm30
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.mm10
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuloader.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoansmenu.mm3
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm58
-rw-r--r--src/plugins/platforms/cocoa/qnsview_keys.mm22
-rw-r--r--src/plugins/platforms/cocoa/qnsview_mouse.mm29
-rw-r--r--src/plugins/platforms/cocoa/qnsview_tablet.mm12
-rw-r--r--src/plugins/platforms/cocoa/qnswindow.mm61
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm6
-rw-r--r--src/plugins/platforms/ios/qiosscreen.mm7
-rw-r--r--src/plugins/platforms/ios/qiostextresponder.mm14
-rw-r--r--src/plugins/platforms/ios/quiview.mm45
-rw-r--r--src/plugins/platforms/platforms.pro2
-rw-r--r--src/plugins/platforms/wasm/main.cpp54
-rw-r--r--src/plugins/platforms/wasm/qtloader.js516
-rw-r--r--src/plugins/platforms/wasm/qtlogo.svg67
-rw-r--r--src/plugins/platforms/wasm/qwasmbackingstore.cpp165
-rw-r--r--src/plugins/platforms/wasm/qwasmbackingstore.h70
-rw-r--r--src/plugins/platforms/wasm/qwasmcompositor.cpp721
-rw-r--r--src/plugins/platforms/wasm/qwasmcompositor.h169
-rw-r--r--src/plugins/platforms/wasm/qwasmcursor.cpp131
-rw-r--r--src/plugins/platforms/wasm/qwasmcursor.h43
-rw-r--r--src/plugins/platforms/wasm/qwasmeventdispatcher.cpp181
-rw-r--r--src/plugins/platforms/wasm/qwasmeventdispatcher.h64
-rw-r--r--src/plugins/platforms/wasm/qwasmeventtranslator.cpp522
-rw-r--r--src/plugins/platforms/wasm/qwasmeventtranslator.h210
-rw-r--r--src/plugins/platforms/wasm/qwasmfontdatabase.cpp86
-rw-r--r--src/plugins/platforms/wasm/qwasmfontdatabase.h49
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.cpp219
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.h92
-rw-r--r--src/plugins/platforms/wasm/qwasmopenglcontext.cpp147
-rw-r--r--src/plugins/platforms/wasm/qwasmopenglcontext.h63
-rw-r--r--src/plugins/platforms/wasm/qwasmscreen.cpp118
-rw-r--r--src/plugins/platforms/wasm/qwasmscreen.h82
-rw-r--r--src/plugins/platforms/wasm/qwasmstylepixmaps_p.h183
-rw-r--r--src/plugins/platforms/wasm/qwasmtheme.cpp50
-rw-r--r--src/plugins/platforms/wasm/qwasmtheme.h56
-rw-r--r--src/plugins/platforms/wasm/qwasmwindow.cpp398
-rw-r--r--src/plugins/platforms/wasm/qwasmwindow.h124
-rw-r--r--src/plugins/platforms/wasm/wasm.json3
-rw-r--r--src/plugins/platforms/wasm/wasm.pro65
-rw-r--r--src/plugins/platforms/wasm/wasm_shell.html61
-rw-r--r--src/plugins/platforms/windows/qtwindowsglobal.h1
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp13
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.h2
-rw-r--r--src/plugins/platforms/windows/qwindowspointerhandler.cpp49
-rw-r--r--src/plugins/printsupport/windows/qwindowsprintdevice.cpp21
-rw-r--r--src/plugins/printsupport/windows/qwindowsprintdevice.h2
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac.mm27
-rw-r--r--src/printsupport/kernel/qprintengine_win.cpp14
-rw-r--r--src/testlib/qappletestlogger.cpp76
-rw-r--r--src/tools/moc/cbordevice.h94
-rw-r--r--src/tools/moc/generator.cpp141
-rw-r--r--src/tools/moc/moc.pri6
-rw-r--r--src/widgets/dialogs/qfiledialog.cpp2
-rw-r--r--src/widgets/dialogs/qwizard_win.cpp6
-rw-r--r--src/widgets/graphicsview/qgraphicsitem_p.h4
-rw-r--r--src/widgets/kernel/qopenglwidget.cpp10
-rw-r--r--src/widgets/kernel/qwidget.cpp4
-rw-r--r--src/widgets/styles/qstylesheetstyle.cpp11
-rw-r--r--tests/auto/corelib/io/qsettings/qsettings.pro2
-rw-r--r--tests/auto/corelib/kernel/qmetatype/qmetatype.pro2
-rw-r--r--tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp244
-rw-r--r--tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp3
-rw-r--r--tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp64
-rw-r--r--tests/auto/corelib/plugin/qplugin/tst_qplugin.pro2
-rw-r--r--tests/auto/corelib/tools/qmacautoreleasepool/qmacautoreleasepool.pro1
-rw-r--r--tests/auto/gui/image/qimage/qimage.pro1
-rw-r--r--tests/auto/other/macnativeevents/macnativeevents.pro2
-rw-r--r--tests/auto/other/other.pro2
-rw-r--r--tests/auto/widgets/kernel/qsizepolicy/tst_qsizepolicy.cpp12
-rw-r--r--tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp29
-rw-r--r--util/unicode/main.cpp8
164 files changed, 7623 insertions, 762 deletions
diff --git a/configure.json b/configure.json
index 1f45f2ccb2..8c8118f39a 100644
--- a/configure.json
+++ b/configure.json
@@ -162,7 +162,8 @@
"sources": [
{ "libs": "-lzdll", "condition": "config.msvc" },
{ "libs": "-lzlib", "condition": "config.msvc" },
- { "libs": "-lz", "condition": "!config.msvc" }
+ { "libs": "-lz", "condition": "!config.msvc" },
+ { "libs": "-s USE_ZLIB=1", "condition": "config.wasm" }
]
},
"dbus": {
@@ -613,7 +614,7 @@
},
"use_gold_linker": {
"label": "Using gold linker",
- "condition": "!config.win32 && !config.integrity && tests.use_gold_linker",
+ "condition": "!config.win32 && !config.integrity && !config.wasm && tests.use_gold_linker",
"output": [ "privateConfig", "useGoldLinker" ]
},
"optimize_debug": {
diff --git a/configure.pri b/configure.pri
index 03eacd3c07..805b985fa6 100644
--- a/configure.pri
+++ b/configure.pri
@@ -68,7 +68,7 @@ defineReplace(qtConfFunc_crossCompile) {
}
defineReplace(qtConfFunc_licenseCheck) {
- exists($$QT_SOURCE_TREE/LICENSE.LGPL3)|exists($$QT_SOURCE_TREE/LICENSE.GPL2): \
+ exists($$QT_SOURCE_TREE/LICENSE.LGPL3)|exists($$QT_SOURCE_TREE/LICENSE.GPL2)|exists($$QT_SOURCE_TREE/LICENSE.GPL3): \
hasOpenSource = true
else: \
hasOpenSource = false
@@ -187,8 +187,13 @@ defineReplace(qtConfFunc_licenseCheck) {
theLicense = "GNU Lesser General Public License (LGPL) version 3"
showWhat = "Type 'L' to view the GNU Lesser General Public License version 3 (LGPLv3)."
gpl2Ok = false
+ gpl3Ok = false
winrt {
notTheLicense = "Note: GPL version 2 is not available on WinRT."
+ } else: wasm {
+ gpl3Ok = true
+ theLicense = "GNU General Public License (GPL) version 3"
+ showWhat = "Type 'G' to view the GNU General Public License version 3 (GPLv3)."
} else: $$qtConfEvaluate("features.android-style-assets") {
notTheLicense = "Note: GPL version 2 is not available due to using Android style assets."
} else {
@@ -230,6 +235,8 @@ defineReplace(qtConfFunc_licenseCheck) {
licenseFile = $$QT_SOURCE_TREE/LICENSE.LGPL3
} else: equals(commercial, no):equals(val, g):$$gpl2Ok {
licenseFile = $$QT_SOURCE_TREE/LICENSE.GPL2
+ } else: equals(commercial, no):equals(val, g):$$gpl3Ok {
+ licenseFile = $$QT_SOURCE_TREE/LICENSE.GPL3
} else {
next()
}
@@ -268,6 +275,8 @@ defineTest(qtConfTest_architecture) {
content = $$cat($$test_out_dir/arch.exe, blob)
else: android:exists($$test_out_dir/libarch.so): \
content = $$cat($$test_out_dir/libarch.so, blob)
+ else: wasm:exists($$test_out_dir/arch.wasm): \
+ content = $$cat($$test_out_dir/arch.wasm, blob)
else: \
error("$$eval($${1}.label) detection binary not found.")
diff --git a/examples/widgets/widgets/tablet/tabletcanvas.cpp b/examples/widgets/widgets/tablet/tabletcanvas.cpp
index 3ff26d2ec8..bfcc84e182 100644
--- a/examples/widgets/widgets/tablet/tabletcanvas.cpp
+++ b/examples/widgets/widgets/tablet/tabletcanvas.cpp
@@ -148,12 +148,14 @@ void TabletCanvas::initPixmap()
m_pixmap = newPixmap;
}
-void TabletCanvas::paintEvent(QPaintEvent *)
+void TabletCanvas::paintEvent(QPaintEvent *event)
{
if (m_pixmap.isNull())
initPixmap();
QPainter painter(this);
- painter.drawPixmap(0, 0, m_pixmap);
+ QRect pixmapPortion = QRect(event->rect().topLeft() * devicePixelRatioF(),
+ event->rect().size() * devicePixelRatioF());
+ painter.drawPixmap(event->rect().topLeft(), m_pixmap, pixmapPortion);
}
//! [4]
diff --git a/mkspecs/features/toolchain.prf b/mkspecs/features/toolchain.prf
index bce3ef3954..4ecfb8d889 100644
--- a/mkspecs/features/toolchain.prf
+++ b/mkspecs/features/toolchain.prf
@@ -34,7 +34,9 @@ isEmpty($${target_prefix}.INCDIRS) {
#
# Get default include and library paths from compiler
#
- gcc {
+ wasm {
+ # wasm compiler does not work here, just use defaults
+ } else: gcc {
cmd_suffix = "<$$QMAKE_SYSTEM_NULL_DEVICE >$$QMAKE_SYSTEM_NULL_DEVICE"
equals(QMAKE_HOST.os, Windows): \
cmd_prefix = "set LC_ALL=C&"
diff --git a/mkspecs/features/uikit/default_pre.prf b/mkspecs/features/uikit/default_pre.prf
index 6a44a67bca..ea6882fbc8 100644
--- a/mkspecs/features/uikit/default_pre.prf
+++ b/mkspecs/features/uikit/default_pre.prf
@@ -24,5 +24,3 @@ load(default_pre)
!versionAtLeast(QMAKE_XCODE_VERSION, 4.3): \
error("This mkspec requires Xcode 4.3 or later")
-ios:shared:!versionAtLeast(QMAKE_IOS_DEPLOYMENT_TARGET, 8.0): \
- QMAKE_IOS_DEPLOYMENT_TARGET = 8.0
diff --git a/mkspecs/features/wasm/qt.prf b/mkspecs/features/wasm/qt.prf
new file mode 100644
index 0000000000..9b9b58d3de
--- /dev/null
+++ b/mkspecs/features/wasm/qt.prf
@@ -0,0 +1,12 @@
+
+qt_depends = $$resolve_depends(QT, "QT.")
+equals(TEMPLATE, app):contains(qt_depends, gui(-private)?) {
+ LIBS *= -L$$[QT_INSTALL_PLUGINS/get]/platforms
+
+ lib_name = wasm
+ lib_path_and_base = $$[QT_INSTALL_PLUGINS/get]/platforms/lib$${lib_name}$$qtPlatformTargetSuffix()
+ LIBS += -l$${lib_name}$$qtPlatformTargetSuffix() $$fromfile($${lib_path_and_base}.prl, QMAKE_PRL_LIBS)
+}
+
+load(qt)
+
diff --git a/mkspecs/features/wasm/wasm.prf b/mkspecs/features/wasm/wasm.prf
new file mode 100644
index 0000000000..278a6719c7
--- /dev/null
+++ b/mkspecs/features/wasm/wasm.prf
@@ -0,0 +1,81 @@
+
+# DESTDIR will be empty if not set in the app .pro file; make sure it has a value
+isEmpty(DESTDIR): DESTDIR = $$OUT_PWD
+
+# Create js and wasm files for applications
+contains(TEMPLATE, .*app) {
+ TARGET_BASE = $${TARGET}
+ TARGET_HTML = $${TARGET}.html
+ TARGET_JS = $${TARGET}.js
+
+ # Make the emscripten compiler generate a js file
+ TARGET = $$TARGET_JS
+
+ QMAKE_INCDIR += $$(HOME)/.emscripten_ports/openssl/include
+
+ CONFIG += static
+ js_file.files = $$TARGET_JS
+ js_file.path = $$target.path
+ isEmpty(js_file.path): \
+ js_file.path += ./
+ INSTALLS += js_file
+
+ # Copy hosting html and javascript to the application build directory.
+ exists($$[QT_INSTALL_PLUGINS]/platforms/wasm_shell.html) {
+ # don't pass this until it's installed somewhere
+ # otherwise makespec test fails during qt configure
+ WASM_PLUGIN_PATH = $$[QT_INSTALL_PLUGINS]/platforms
+ } else {
+ ## internal build. not installed
+ WASM_PLUGIN_PATH = $$PWD/../../../src/plugins/platforms/wasm
+ }
+
+ # Copy/Generate main .html file (e.g. myapp.html) from the webassembly_shell.html by
+ # replacing the app name placeholder with the actual app name.
+ apphtml.name = application main html file
+ apphtml.output = $$DESTDIR/$$TARGET_HTML
+ apphtml.commands = sed -e s/APPNAME/$$TARGET_BASE/g $$WASM_PLUGIN_PATH/wasm_shell.html > $$DESTDIR/$$TARGET_HTML
+ apphtml.input = $$WASM_PLUGIN_PATH/wasm_shell.html
+ apphtml.depends = $$apphtml.input
+ QMAKE_EXTRA_COMPILERS += apphtml
+
+ appjs.name = application qtloader.js
+ appjs.output = $$DESTDIR/qtloader.js
+ appjs.commands = $$QMAKE_COPY $$WASM_PLUGIN_PATH/qtloader.js $$DESTDIR
+ appjs.input = $$WASM_PLUGIN_PATH/qtloader.js
+ appjs.depends = $$appjs.input
+ QMAKE_EXTRA_COMPILERS += appjs
+
+ appsvg.name = application qtlogo.svg
+ appsvg.output = $$DESTDIR/qtlogo.svg
+ appsvg.commands = $$QMAKE_COPY $$WASM_PLUGIN_PATH/qtlogo.svg $$DESTDIR
+ appsvg.input = $$WASM_PLUGIN_PATH/qtlogo.svg
+ appsvg.depends = $$appsvg.input
+ QMAKE_EXTRA_COMPILERS += appsvg
+
+ QMAKE_EXTRA_TARGETS += apphtml appjs appsvg
+ POST_TARGETDEPS += apphtml appjs appsvg
+
+ # Add manual target to make "make -B shellfiles" work.
+ shellfiles.target = shellfiles
+ shellfiles.depends = apphtml appjs appsvg
+ QMAKE_EXTRA_TARGETS += shellfiles
+
+ # emscripten ports are linked into the main module (this app), not the Qt
+ # libs which reference them
+ qt {
+ qt_depends = $$resolve_depends(QT, "QT.")
+ contains(qt_depends, core(-private)?): QMAKE_LFLAGS += \
+ $$QMAKE_LIBS_THREAD $$QMAKE_LIBS_ZLIB
+ contains(qt_depends, gui(-private)?): QMAKE_LFLAGS += \
+ $$QMAKE_LIBS_FREETYPE $$QMAKE_LIBS_LIBPNG
+ }
+}
+
+# Creates the stand-alone version of the library from bitcode
+!static:contains(TEMPLATE, .*lib): {
+ load(resolve_target)
+ QMAKE_POST_LINK += $$QMAKE_LINK_SHLIB $$QMAKE_RESOLVED_TARGET -o $${QMAKE_RESOLVED_TARGET}.js
+
+ QMAKE_INCDIR += $$(HOME)/.emscripten_ports/openssl/include
+}
diff --git a/mkspecs/wasm-emscripten/qmake.conf b/mkspecs/wasm-emscripten/qmake.conf
new file mode 100644
index 0000000000..c3b67310c8
--- /dev/null
+++ b/mkspecs/wasm-emscripten/qmake.conf
@@ -0,0 +1,90 @@
+# qmake configuration for building with emscripten
+MAKEFILE_GENERATOR = UNIX
+QMAKE_PLATFORM = wasm unix
+
+include(../common/gcc-base.conf)
+include(../common/clang.conf)
+
+EMTERP_FLAGS = \
+ -s EMTERPRETIFY=1 \
+ -s EMTERPRETIFY_ASYNC=1 \
+ -s \"EMTERPRETIFY_FILE=\'data.binary\'\" \
+ -s ASSERTIONS=1 \
+ --profiling-funcs
+
+EMCC_COMMON_CFLAGS = \
+ -s USE_LIBPNG=1 \
+ -s USE_FREETYPE=1 \
+ -s USE_ZLIB=1
+
+EMCC_COMMON_LFLAGS = \
+ -s WASM=1 \
+ -s FULL_ES2=1 \
+ -s ALLOW_MEMORY_GROWTH=1 \
+ -s USE_WEBGL2=1 \
+ -s NO_EXIT_RUNTIME=0 \
+ -s ERROR_ON_UNDEFINED_SYMBOLS=1 \
+ --bind \
+ -s \"BINARYEN_METHOD=\'native-wasm\'\" \
+ -s \"BINARYEN_TRAP_MODE=\'clamp\'\"
+
+EMCC_COMMON_LFLAGS_DEBUG = \
+ $$EMCC_COMMON_LFLAGS \
+ -s ASSERTIONS=2 \
+ -s DEMANGLE_SUPPORT=1 \
+ # -s LIBRARY_DEBUG=1 \ #print out library calls, verbose
+ # -s SYSCALL_DEBUG=1 \ #print out sys calls, verbose
+ # -s FS_LOG=1 \ #print out filesystem ops, verbose
+ # -s SOCKET_DEBUG \ #print out socket,network data transfer
+ -s GL_DEBUG=1
+
+# the -s arguments can also be used with release builds
+# but here in debug for clarity
+
+QMAKE_COMPILER += emscripten
+
+QMAKE_CC = emcc
+QMAKE_CXX = em++
+
+QMAKE_CFLAGS += $$EMCC_COMMON_CFLAGS
+QMAKE_CXXFLAGS += $$EMCC_COMMON_CFLAGS
+
+# Practical debugging setup:
+# "-g4" preserves function names for stack traces
+# "-Os" produces reasonably sized binaries
+QMAKE_CFLAGS_DEBUG -= -g
+QMAKE_CXXFLAGS_DEBUG -= -g
+QMAKE_CFLAGS_DEBUG += -Os -g4
+QMAKE_CXXFLAGS_DEBUG += -Os -g4
+QMAKE_LFLAGS_DEBUG += -Os -g4
+
+QMAKE_CXXFLAGS_RELEASE -= -O2
+QMAKE_CXXFLAGS_RELEASE += -O3
+QMAKE_CFLAGS_RELEASE -= -O2
+QMAKE_CFLAGS_RELEASE += -O3
+QMAKE_LFLAGS_RELEASE += -O3
+MAKE_CFLAGS_OPTIMIZE += -O3
+MAKE_CFLAGS_OPTIMIZE_FULL += -Oz
+
+QMAKE_LINK = $$QMAKE_CXX
+QMAKE_LINK_SHLIB = $$QMAKE_CXX
+QMAKE_LINK_C = $$QMAKE_CC
+QMAKE_LINK_C_SHLIB = $$QMAKE_CC
+
+QMAKE_LIBS_THREAD = $$QMAKE_CFLAGS_THREAD
+
+QMAKE_LFLAGS += $$EMCC_COMMON_LFLAGS
+QMAKE_LFLAGS_DEBUG += $$EMCC_COMMON_LFLAGS_DEBUG
+
+QMAKE_PREFIX_SHLIB = lib
+QMAKE_EXTENSION_SHLIB = so # llvm bitcode, linked to js in post_link
+QMAKE_PREFIX_STATICLIB = lib
+QMAKE_EXTENSION_STATICLIB = a # llvm bitcode
+
+QMAKE_AR = emar cqs
+QMAKE_DISTCLEAN += *.html *.js *.wasm
+
+QT_QPA_DEFAULT_PLATFORM = wasm
+
+QTPLUGIN.platforms = wasm
+load(qt_config)
diff --git a/mkspecs/wasm-emscripten/qplatformdefs.h b/mkspecs/wasm-emscripten/qplatformdefs.h
new file mode 100644
index 0000000000..c1a0d7b1a8
--- /dev/null
+++ b/mkspecs/wasm-emscripten/qplatformdefs.h
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the qmake spec of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPLATFORMDEFS_H
+#define QPLATFORMDEFS_H
+
+// Get Qt defines/settings
+
+#include "qglobal.h"
+
+// Set any POSIX/XOPEN defines at the top of this file to turn on specific APIs
+
+// 1) need to reset default environment if _BSD_SOURCE is defined
+// 2) need to specify POSIX thread interfaces explicitly in glibc 2.0
+// 3) it seems older glibc need this to include the X/Open stuff
+
+#include <unistd.h>
+
+// We are hot - unistd.h should have turned on the specific APIs we requested
+
+#include <features.h>
+#include <pthread.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <pwd.h>
+#include <signal.h>
+#include <dlfcn.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/ipc.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#ifndef QT_NO_IPV6IFNAME
+#include <net/if.h>
+#endif
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+
+#ifdef QT_LARGEFILE_SUPPORT
+#define QT_STATBUF struct stat64
+#define QT_STATBUF4TSTAT struct stat64
+#define QT_STAT ::stat64
+#define QT_FSTAT ::fstat64
+#define QT_LSTAT ::lstat64
+#define QT_OPEN ::open64
+#define QT_TRUNCATE ::truncate64
+#define QT_FTRUNCATE ::ftruncate64
+#define QT_LSEEK ::lseek64
+#else
+#define QT_STATBUF struct stat
+#define QT_STATBUF4TSTAT struct stat
+#define QT_STAT ::stat
+#define QT_FSTAT ::fstat
+#define QT_LSTAT ::lstat
+#define QT_OPEN ::open
+#define QT_TRUNCATE ::truncate
+#define QT_FTRUNCATE ::ftruncate
+#define QT_LSEEK ::lseek
+#endif
+
+#ifdef QT_LARGEFILE_SUPPORT
+#define QT_FOPEN ::fopen64
+#define QT_FSEEK ::fseeko64
+#define QT_FTELL ::ftello64
+#define QT_FGETPOS ::fgetpos64
+#define QT_FSETPOS ::fsetpos64
+#define QT_MMAP ::mmap64
+#define QT_FPOS_T fpos64_t
+#define QT_OFF_T off64_t
+#else
+#define QT_FOPEN ::fopen
+#define QT_FSEEK ::fseek
+#define QT_FTELL ::ftell
+#define QT_FGETPOS ::fgetpos
+#define QT_FSETPOS ::fsetpos
+#define QT_MMAP ::mmap
+#define QT_FPOS_T fpos_t
+#define QT_OFF_T long
+#endif
+
+#define QT_STAT_REG S_IFREG
+#define QT_STAT_DIR S_IFDIR
+#define QT_STAT_MASK S_IFMT
+#define QT_STAT_LNK S_IFLNK
+#define QT_SOCKET_CONNECT ::connect
+#define QT_SOCKET_BIND ::bind
+#define QT_FILENO fileno
+#define QT_CLOSE ::close
+#define QT_READ ::read
+#define QT_WRITE ::write
+#define QT_ACCESS ::access
+#define QT_GETCWD ::getcwd
+#define QT_CHDIR ::chdir
+#define QT_MKDIR ::mkdir
+#define QT_RMDIR ::rmdir
+#define QT_OPEN_LARGEFILE O_LARGEFILE
+#define QT_OPEN_RDONLY O_RDONLY
+#define QT_OPEN_WRONLY O_WRONLY
+#define QT_OPEN_RDWR O_RDWR
+#define QT_OPEN_CREAT O_CREAT
+#define QT_OPEN_TRUNC O_TRUNC
+#define QT_OPEN_APPEND O_APPEND
+#define QT_OPEN_EXCL O_EXCL
+
+// Directory iteration
+#define QT_DIR DIR
+
+#define QT_OPENDIR ::opendir
+#define QT_CLOSEDIR ::closedir
+
+#if defined(QT_LARGEFILE_SUPPORT) \
+ && defined(QT_USE_XOPEN_LFS_EXTENSIONS) \
+ && !defined(QT_NO_READDIR64)
+#define QT_DIRENT struct dirent64
+#define QT_READDIR ::readdir64
+#define QT_READDIR_R ::readdir64_r
+#else
+#define QT_DIRENT struct dirent
+#define QT_READDIR ::readdir
+#define QT_READDIR_R ::readdir_r
+#endif
+
+#define QT_SOCKET_CONNECT ::connect
+#define QT_SOCKET_BIND ::bind
+
+
+#define QT_SIGNAL_RETTYPE void
+#define QT_SIGNAL_ARGS int
+#define QT_SIGNAL_IGNORE SIG_IGN
+
+#define QT_SOCKLEN_T socklen_t
+
+#if defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)
+#define QT_SNPRINTF ::snprintf
+#define QT_VSNPRINTF ::vsnprintf
+#endif
+
+#endif // QPLATFORMDEFS_H
diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp
index cae179cc93..7c359071bf 100644
--- a/qmake/generators/makefile.cpp
+++ b/qmake/generators/makefile.cpp
@@ -1102,18 +1102,7 @@ MakefileGenerator::write()
QString
MakefileGenerator::prlFileName(bool fixify)
{
- QString ret = project->first("TARGET_PRL").toQString();
- if(ret.isEmpty())
- ret = project->first("TARGET").toQString();
- int slsh = ret.lastIndexOf(Option::dir_sep);
- if(slsh != -1)
- ret.remove(0, slsh);
- if(!ret.endsWith(Option::prl_ext)) {
- int dot = ret.indexOf('.');
- if(dot != -1)
- ret.truncate(dot);
- ret += Option::prl_ext;
- }
+ QString ret = project->first("PRL_TARGET") + Option::prl_ext;
if(!project->isEmpty("QMAKE_BUNDLE"))
ret.prepend(project->first("QMAKE_BUNDLE") + Option::dir_sep);
if(fixify) {
diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp
index 2ed1866584..ab946fa439 100644
--- a/qmake/generators/unix/unixmake2.cpp
+++ b/qmake/generators/unix/unixmake2.cpp
@@ -1244,7 +1244,8 @@ void UnixMakefileGenerator::init2()
if(!project->isEmpty("TARGET"))
project->values("TARGET").first().prepend(project->first("DESTDIR"));
} else if (project->isActiveConfig("staticlib")) {
- project->values("TARGET").first().prepend(project->first("QMAKE_PREFIX_STATICLIB"));
+ project->values("PRL_TARGET") =
+ project->values("TARGET").first().prepend(project->first("QMAKE_PREFIX_STATICLIB"));
project->values("TARGET").first() += "." + project->first("QMAKE_EXTENSION_STATICLIB");
if(project->values("QMAKE_AR_CMD").isEmpty())
project->values("QMAKE_AR_CMD").append("$(AR) $(DESTDIR)$(TARGET) $(OBJECTS)");
@@ -1278,6 +1279,7 @@ void UnixMakefileGenerator::init2()
QString prefix;
if(!project->isActiveConfig("no_plugin_name_prefix"))
prefix = "lib";
+ project->values("PRL_TARGET").prepend(prefix + project->first("TARGET"));
project->values("TARGET_x.y.z").append(prefix +
project->first("TARGET") + "." +
project->first("QMAKE_EXTENSION_PLUGIN"));
@@ -1291,6 +1293,7 @@ void UnixMakefileGenerator::init2()
"." + project->first("VER_MAJ"));
project->values("TARGET") = project->values("TARGET_x.y.z");
} else if (!project->isEmpty("QMAKE_HPUX_SHLIB")) {
+ project->values("PRL_TARGET").prepend("lib" + project->first("TARGET"));
project->values("TARGET_").append("lib" + project->first("TARGET") + ".sl");
if(project->isActiveConfig("lib_version_first"))
project->values("TARGET_x").append("lib" + project->first("VER_MAJ") + "." +
@@ -1300,6 +1303,7 @@ void UnixMakefileGenerator::init2()
project->first("VER_MAJ"));
project->values("TARGET") = project->values("TARGET_x");
} else if (!project->isEmpty("QMAKE_AIX_SHLIB")) {
+ project->values("PRL_TARGET").prepend("lib" + project->first("TARGET"));
project->values("TARGET_").append(project->first("QMAKE_PREFIX_STATICLIB") + project->first("TARGET")
+ "." + project->first("QMAKE_EXTENSION_STATICLIB"));
if(project->isActiveConfig("lib_version_first")) {
@@ -1331,6 +1335,7 @@ void UnixMakefileGenerator::init2()
}
project->values("TARGET") = project->values("TARGET_x.y.z");
} else {
+ project->values("PRL_TARGET").prepend("lib" + project->first("TARGET"));
project->values("TARGET_").append("lib" + project->first("TARGET") + "." +
project->first("QMAKE_EXTENSION_SHLIB"));
if(project->isActiveConfig("lib_version_first")) {
diff --git a/qmake/generators/win32/mingw_make.cpp b/qmake/generators/win32/mingw_make.cpp
index 95f69dbbc3..13412e971a 100644
--- a/qmake/generators/win32/mingw_make.cpp
+++ b/qmake/generators/win32/mingw_make.cpp
@@ -204,8 +204,6 @@ void MingwMakefileGenerator::init()
return;
}
- project->values("TARGET_PRL").append(project->first("TARGET"));
-
processVars();
project->values("QMAKE_LIBS") += project->values("RES_FILE");
diff --git a/qmake/generators/win32/winmakefile.cpp b/qmake/generators/win32/winmakefile.cpp
index 3c730299be..1388e120e7 100644
--- a/qmake/generators/win32/winmakefile.cpp
+++ b/qmake/generators/win32/winmakefile.cpp
@@ -185,7 +185,8 @@ void Win32MakefileGenerator::processVars()
if (project->first("TEMPLATE").endsWith("aux"))
return;
- project->values("QMAKE_ORIG_TARGET") = project->values("TARGET");
+ project->values("PRL_TARGET") =
+ project->values("QMAKE_ORIG_TARGET") = project->values("TARGET");
if (project->isEmpty("QMAKE_PROJECT_NAME"))
project->values("QMAKE_PROJECT_NAME") = project->values("QMAKE_ORIG_TARGET");
else if (project->first("TEMPLATE").startsWith("vc"))
diff --git a/src/3rdparty/double-conversion/include/double-conversion/utils.h b/src/3rdparty/double-conversion/include/double-conversion/utils.h
index ca7646d817..ff00855bea 100644
--- a/src/3rdparty/double-conversion/include/double-conversion/utils.h
+++ b/src/3rdparty/double-conversion/include/double-conversion/utils.h
@@ -77,7 +77,7 @@ inline void abort_noreturn() { abort(); }
defined(__SH4__) || defined(__alpha__) || \
defined(_MIPS_ARCH_MIPS32R2) || \
defined(__AARCH64EL__) || defined(__aarch64__) || \
- defined(__riscv)
+ defined(__riscv) || defined(__EMSCRIPTEN__)
#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
#elif defined(__mc68000__)
#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS
diff --git a/src/3rdparty/tinycbor/src/cborinternal_p.h b/src/3rdparty/tinycbor/src/cborinternal_p.h
index 8d77f28466..c5fe63003f 100644
--- a/src/3rdparty/tinycbor/src/cborinternal_p.h
+++ b/src/3rdparty/tinycbor/src/cborinternal_p.h
@@ -27,6 +27,75 @@
#include "compilersupport_p.h"
+#ifndef CBOR_NO_FLOATING_POINT
+# include <float.h>
+# include <math.h>
+#else
+# ifndef CBOR_NO_HALF_FLOAT_TYPE
+# define CBOR_NO_HALF_FLOAT_TYPE 1
+# endif
+#endif
+
+#ifndef CBOR_NO_HALF_FLOAT_TYPE
+# ifdef __F16C__
+# include <immintrin.h>
+static inline unsigned short encode_half(double val)
+{
+ return _cvtss_sh((float)val, 3);
+}
+static inline double decode_half(unsigned short half)
+{
+ return _cvtsh_ss(half);
+}
+# else
+/* software implementation of float-to-fp16 conversions */
+static inline unsigned short encode_half(double val)
+{
+ uint64_t v;
+ int sign, exp, mant;
+ memcpy(&v, &val, sizeof(v));
+ sign = v >> 63 << 15;
+ exp = (v >> 52) & 0x7ff;
+ mant = v << 12 >> 12 >> (53-11); /* keep only the 11 most significant bits of the mantissa */
+ exp -= 1023;
+ if (exp == 1024) {
+ /* infinity or NaN */
+ exp = 16;
+ mant >>= 1;
+ } else if (exp >= 16) {
+ /* overflow, as largest number */
+ exp = 15;
+ mant = 1023;
+ } else if (exp >= -14) {
+ /* regular normal */
+ } else if (exp >= -24) {
+ /* subnormal */
+ mant |= 1024;
+ mant >>= -(exp + 14);
+ exp = -15;
+ } else {
+ /* underflow, make zero */
+ return 0;
+ }
+
+ /* safe cast here as bit operations above guarantee not to overflow */
+ return (unsigned short)(sign | ((exp + 15) << 10) | mant);
+}
+
+/* this function was copied & adapted from RFC 7049 Appendix D */
+static inline double decode_half(unsigned short half)
+{
+ int exp = (half >> 10) & 0x1f;
+ int mant = half & 0x3ff;
+ double val;
+ if (exp == 0) val = ldexp(mant, -24);
+ else if (exp != 31) val = ldexp(mant + 1024, exp - 25);
+ else val = mant == 0 ? INFINITY : NAN;
+ return half & 0x8000 ? -val : val;
+}
+# endif
+#endif /* CBOR_NO_HALF_FLOAT_TYPE */
+
#ifndef CBOR_INTERNAL_API
# define CBOR_INTERNAL_API
#endif
diff --git a/src/3rdparty/tinycbor/src/compilersupport_p.h b/src/3rdparty/tinycbor/src/compilersupport_p.h
index dc4c4cfd8a..2b9491d34d 100644
--- a/src/3rdparty/tinycbor/src/compilersupport_p.h
+++ b/src/3rdparty/tinycbor/src/compilersupport_p.h
@@ -36,8 +36,6 @@
#ifndef assert
# include <assert.h>
#endif
-#include <float.h>
-#include <math.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
@@ -46,10 +44,6 @@
# include <stdbool.h>
#endif
-#ifdef __F16C__
-# include <immintrin.h>
-#endif
-
#if __STDC_VERSION__ >= 201112L || __cplusplus >= 201103L || __cpp_static_assert >= 200410
# define cbor_static_assert(x) static_assert(x, #x)
#elif !defined(__cplusplus) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406) && (__STDC_VERSION__ > 199901L)
@@ -207,58 +201,5 @@ static inline bool add_check_overflow(size_t v1, size_t v2, size_t *r)
#endif
}
-static inline unsigned short encode_half(double val)
-{
-#ifdef __F16C__
- return _cvtss_sh((float)val, 3);
-#else
- uint64_t v;
- int sign, exp, mant;
- memcpy(&v, &val, sizeof(v));
- sign = v >> 63 << 15;
- exp = (v >> 52) & 0x7ff;
- mant = v << 12 >> 12 >> (53-11); /* keep only the 11 most significant bits of the mantissa */
- exp -= 1023;
- if (exp == 1024) {
- /* infinity or NaN */
- exp = 16;
- mant >>= 1;
- } else if (exp >= 16) {
- /* overflow, as largest number */
- exp = 15;
- mant = 1023;
- } else if (exp >= -14) {
- /* regular normal */
- } else if (exp >= -24) {
- /* subnormal */
- mant |= 1024;
- mant >>= -(exp + 14);
- exp = -15;
- } else {
- /* underflow, make zero */
- return 0;
- }
-
- /* safe cast here as bit operations above guarantee not to overflow */
- return (unsigned short)(sign | ((exp + 15) << 10) | mant);
-#endif
-}
-
-/* this function was copied & adapted from RFC 7049 Appendix D */
-static inline double decode_half(unsigned short half)
-{
-#ifdef __F16C__
- return _cvtsh_ss(half);
-#else
- int exp = (half >> 10) & 0x1f;
- int mant = half & 0x3ff;
- double val;
- if (exp == 0) val = ldexp(mant, -24);
- else if (exp != 31) val = ldexp(mant + 1024, exp - 25);
- else val = mant == 0 ? INFINITY : NAN;
- return half & 0x8000 ? -val : val;
-#endif
-}
-
#endif /* COMPILERSUPPORT_H */
diff --git a/src/3rdparty/wasm/DejaVuSans.ttf b/src/3rdparty/wasm/DejaVuSans.ttf
new file mode 100644
index 0000000000..7e411a71be
--- /dev/null
+++ b/src/3rdparty/wasm/DejaVuSans.ttf
Binary files differ
diff --git a/src/3rdparty/wasm/LICENSE b/src/3rdparty/wasm/LICENSE
new file mode 100644
index 0000000000..4f9e8544b7
--- /dev/null
+++ b/src/3rdparty/wasm/LICENSE
@@ -0,0 +1,15 @@
+Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license (“Fonts”) and associated documentation files (the “Font Software”), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions:
+
+The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces.
+
+The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words “Bitstream” or the word “Vera”.
+
+This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the “Bitstream Vera” names.
+
+The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself.
+
+THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
+
+Except as contained in this notice, the names of GNOME, the GNOME Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the GNOME Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.
diff --git a/src/3rdparty/wasm/Vera.ttf b/src/3rdparty/wasm/Vera.ttf
new file mode 100644
index 0000000000..58cd6b5e61
--- /dev/null
+++ b/src/3rdparty/wasm/Vera.ttf
Binary files differ
diff --git a/src/3rdparty/wasm/qt_attribution.json b/src/3rdparty/wasm/qt_attribution.json
new file mode 100644
index 0000000000..184e2968cd
--- /dev/null
+++ b/src/3rdparty/wasm/qt_attribution.json
@@ -0,0 +1,21 @@
+{
+ "Id": "vera_font",
+ "Name": "Vera",
+ "QDocModule": "qtcore",
+ "QtUsage": "Used for WebAssembly platform.",
+
+ "License": "Bitstream",
+ "LicenseFile": "LICENSE",
+ "Copyright": "Copyright (C) 2003 Bitstream,Inc"
+},
+{
+ "Id": "dejayvu",
+ "Name": "DejaVuSans",
+ "QDocModule": "qtcore",
+ "QtUsage": "Used for WebAssembly platform.",
+
+ "License": "Bitstream",
+ "LicenseFile": "LICENSE",
+ "Copyright": "Copyright (C) 2003 Bitstream,Inc"
+}
+
diff --git a/src/corelib/codecs/qtextcodec_p.h b/src/corelib/codecs/qtextcodec_p.h
index f3c2d090c9..be0cab93e6 100644
--- a/src/corelib/codecs/qtextcodec_p.h
+++ b/src/corelib/codecs/qtextcodec_p.h
@@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE
#ifndef QT_NO_TEXTCODEC
-#if defined(Q_OS_MAC) || defined(Q_OS_ANDROID) || defined(Q_OS_QNX)
+#if defined(Q_OS_MAC) || defined(Q_OS_ANDROID) || defined(Q_OS_QNX) || defined(Q_OS_WASM)
#define QT_LOCALE_IS_UTF8
#endif
diff --git a/src/corelib/configure.json b/src/corelib/configure.json
index 18fc22f18f..183eb3a13e 100644
--- a/src/corelib/configure.json
+++ b/src/corelib/configure.json
@@ -481,7 +481,7 @@
},
"eventfd": {
"label": "eventfd",
- "condition": "tests.eventfd",
+ "condition": "!config.wasm && tests.eventfd",
"output": [ "feature" ]
},
"futimens": {
@@ -592,7 +592,7 @@
"poll_ppoll": {
"label": "Native ppoll()",
"emitIf": "!config.win32",
- "condition": "tests.ppoll",
+ "condition": "!config.wasm && tests.ppoll",
"output": [ "privateFeature" ]
},
"poll_pollts": {
diff --git a/src/corelib/global/archdetect.cpp b/src/corelib/global/archdetect.cpp
index 6c1a026fa8..422df3ff90 100644
--- a/src/corelib/global/archdetect.cpp
+++ b/src/corelib/global/archdetect.cpp
@@ -51,6 +51,8 @@
# define ARCH_PROCESSOR "avr32"
#elif defined(Q_PROCESSOR_BLACKFIN)
# define ARCH_PROCESSOR "bfin"
+#elif defined(Q_PROCESSOR_WASM)
+# define ARCH_PROCESSOR "wasm"
#elif defined(Q_PROCESSOR_X86_32)
# define ARCH_PROCESSOR "i386"
#elif defined(Q_PROCESSOR_X86_64)
diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h
index 2b85ea0815..345ab9e8ad 100644
--- a/src/corelib/global/qcompilerdetection.h
+++ b/src/corelib/global/qcompilerdetection.h
@@ -206,6 +206,9 @@
# define Q_DECL_NS_RETURNS_AUTORELEASED __attribute__((ns_returns_autoreleased))
# endif
# endif
+# ifdef __EMSCRIPTEN__
+# define Q_CC_EMSCRIPTEN
+# endif
# else
/* Plain GCC */
# if Q_CC_GNU >= 405
diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp
index a931b43220..9f47b8eb98 100644
--- a/src/corelib/global/qlogging.cpp
+++ b/src/corelib/global/qlogging.cpp
@@ -94,6 +94,10 @@
# include "private/qcore_unix_p.h"
#endif
+#ifdef Q_OS_WASM
+#include <emscripten/emscripten.h>
+#endif
+
#if QT_CONFIG(regularexpression)
# ifdef __UCLIBC__
# if __UCLIBC_HAS_BACKTRACE__
@@ -1690,6 +1694,37 @@ static bool win_message_handler(QtMsgType type, const QMessageLogContext &contex
}
#endif
+#ifdef Q_OS_WASM
+static bool wasm_default_message_handler(QtMsgType type,
+ const QMessageLogContext &context,
+ const QString &message)
+{
+ if (shouldLogToStderr())
+ return false; // Leave logging up to stderr handler
+
+ QString formattedMessage = qFormatLogMessage(type, context, message);
+ int emOutputFlags = (EM_LOG_CONSOLE | EM_LOG_DEMANGLE);
+ QByteArray localMsg = message.toLocal8Bit();
+ switch (type) {
+ case QtDebugMsg:
+ break;
+ case QtInfoMsg:
+ break;
+ case QtWarningMsg:
+ emOutputFlags |= EM_LOG_WARN;
+ break;
+ case QtCriticalMsg:
+ emOutputFlags |= EM_LOG_ERROR;
+ break;
+ case QtFatalMsg:
+ emOutputFlags |= EM_LOG_ERROR;
+ }
+ emscripten_log(emOutputFlags, "%s\n", qPrintable(formattedMessage));
+
+ return true; // Prevent further output to stderr
+}
+#endif
+
#endif // Bootstrap check
// --------------------------------------------------------------------------
@@ -1733,8 +1768,9 @@ static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &con
# elif defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
handledStderr |= android_default_message_handler(type, context, message);
# elif defined(QT_USE_APPLE_UNIFIED_LOGGING)
- if (__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *))
- handledStderr |= AppleUnifiedLogger::messageHandler(type, context, message);
+ handledStderr |= AppleUnifiedLogger::messageHandler(type, context, message);
+# elif defined Q_OS_WASM
+ handledStderr |= wasm_default_message_handler(type, context, message);
# endif
#endif
diff --git a/src/corelib/global/qoperatingsystemversion_win.cpp b/src/corelib/global/qoperatingsystemversion_win.cpp
index 7659fb2550..2da190da48 100644
--- a/src/corelib/global/qoperatingsystemversion_win.cpp
+++ b/src/corelib/global/qoperatingsystemversion_win.cpp
@@ -103,7 +103,7 @@ static inline OSVERSIONINFOEX determineWinOsVersion()
// GetVersionEx() has been deprecated in Windows 8.1 and will return
// only Windows 8 from that version on, so use the kernel API function.
- pRtlGetVersion((LPOSVERSIONINFO) &result); // always returns STATUS_SUCCESS
+ pRtlGetVersion(reinterpret_cast<LPOSVERSIONINFO>(&result)); // always returns STATUS_SUCCESS
#else // !Q_OS_WINCE
GetVersionEx(&result);
#endif
diff --git a/src/corelib/global/qprocessordetection.h b/src/corelib/global/qprocessordetection.h
index 9a3dfd776d..aaa27dff4a 100644
--- a/src/corelib/global/qprocessordetection.h
+++ b/src/corelib/global/qprocessordetection.h
@@ -320,6 +320,12 @@
# endif
# define Q_BYTE_ORDER Q_BIG_ENDIAN
+// -- Web Assembly --
+#elif defined(__EMSCRIPTEN__)
+# define Q_PROCESSOR_WASM
+# define Q_PROCESSOR_X86 6 // enables SIMD support
+# define Q_BYTE_ORDER Q_LITTLE_ENDIAN
+# define Q_PROCESSOR_WORDSIZE 8
#endif
/*
diff --git a/src/corelib/global/qsystemdetection.h b/src/corelib/global/qsystemdetection.h
index cacb95b674..aabe46f3c2 100644
--- a/src/corelib/global/qsystemdetection.h
+++ b/src/corelib/global/qsystemdetection.h
@@ -137,6 +137,8 @@
# define Q_OS_HPUX
#elif defined(__native_client__)
# define Q_OS_NACL
+#elif defined(__EMSCRIPTEN__)
+# define Q_OS_WASM
#elif defined(__linux__) || defined(__linux)
# define Q_OS_LINUX
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp
index 835e6a6a44..0159bc4128 100644
--- a/src/corelib/io/qfilesystemengine_unix.cpp
+++ b/src/corelib/io/qfilesystemengine_unix.cpp
@@ -76,9 +76,7 @@
#endif
#if defined(Q_OS_DARWIN)
-# if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(101200, 100000, 100000, 30000)
-# include <sys/clonefile.h>
-# endif
+# include <sys/clonefile.h>
# include <copyfile.h>
// We cannot include <Foundation/Foundation.h> (it's an Objective-C header), but
// we need these declarations:
@@ -860,7 +858,7 @@ QString QFileSystemEngine::resolveUserName(uint userId)
QVarLengthArray<char, 1024> buf(size_max);
#endif
-#if !defined(Q_OS_INTEGRITY)
+#if !defined(Q_OS_INTEGRITY) && !defined(Q_OS_WASM)
struct passwd *pw = 0;
#if QT_CONFIG(thread) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) && !defined(Q_OS_VXWORKS)
struct passwd entry;
@@ -884,7 +882,7 @@ QString QFileSystemEngine::resolveGroupName(uint groupId)
QVarLengthArray<char, 1024> buf(size_max);
#endif
-#if !defined(Q_OS_INTEGRITY)
+#if !defined(Q_OS_INTEGRITY) && !defined(Q_OS_WASM)
struct group *gr = 0;
#if QT_CONFIG(thread) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) && !defined(Q_OS_VXWORKS) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID) && (__ANDROID_API__ >= 24))
size_max = sysconf(_SC_GETGR_R_SIZE_MAX);
@@ -1258,20 +1256,18 @@ bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSy
//static
bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
{
-#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(101200, 100000, 100000, 30000)
- if (__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *)) {
- if (::clonefile(source.nativeFilePath().constData(),
- target.nativeFilePath().constData(), 0) == 0)
- return true;
- error = QSystemError(errno, QSystemError::StandardLibraryError);
- return false;
- }
+#if defined(Q_OS_DARWIN)
+ if (::clonefile(source.nativeFilePath().constData(),
+ target.nativeFilePath().constData(), 0) == 0)
+ return true;
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
#else
Q_UNUSED(source);
Q_UNUSED(target);
-#endif
error = QSystemError(ENOSYS, QSystemError::StandardLibraryError); //Function not implemented
return false;
+#endif
}
//static
@@ -1295,13 +1291,11 @@ bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSy
}
#endif
#if defined(Q_OS_DARWIN) && defined(RENAME_EXCL)
- if (__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *)) {
- if (renameatx_np(AT_FDCWD, srcPath, AT_FDCWD, tgtPath, RENAME_EXCL) == 0)
- return true;
- if (errno != ENOTSUP) {
- error = QSystemError(errno, QSystemError::StandardLibraryError);
- return false;
- }
+ if (renameatx_np(AT_FDCWD, srcPath, AT_FDCWD, tgtPath, RENAME_EXCL) == 0)
+ return true;
+ if (errno != ENOTSUP) {
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
}
#endif
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
index fadc058110..74081b4ffa 100644
--- a/src/corelib/io/qfilesystemengine_win.cpp
+++ b/src/corelib/io/qfilesystemengine_win.cpp
@@ -935,7 +935,7 @@ static bool tryFindFallback(const QFileSystemEntry &fname, QFileSystemMetaData &
bool QFileSystemEngine::fillMetaData(int fd, QFileSystemMetaData &data,
QFileSystemMetaData::MetaDataFlags what)
{
- HANDLE fHandle = (HANDLE)_get_osfhandle(fd);
+ auto fHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
if (fHandle != INVALID_HANDLE_VALUE) {
return fillMetaData(fHandle, data, what);
}
@@ -1014,7 +1014,8 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
WIN32_FIND_DATA findData;
// The memory structure for WIN32_FIND_DATA is same as WIN32_FILE_ATTRIBUTE_DATA
// for all members used by fillFindData().
- bool ok = ::GetFileAttributesEx((wchar_t*)fname.nativeFilePath().utf16(), GetFileExInfoStandard,
+ bool ok = ::GetFileAttributesEx(reinterpret_cast<const wchar_t*>(fname.nativeFilePath().utf16()),
+ GetFileExInfoStandard,
reinterpret_cast<WIN32_FILE_ATTRIBUTE_DATA *>(&findData));
if (ok) {
data.fillFromFindData(findData, false, fname.isDriveRoot());
@@ -1069,19 +1070,22 @@ static bool isDirPath(const QString &dirPath, bool *existed)
if (path.length() == 2 && path.at(1) == QLatin1Char(':'))
path += QLatin1Char('\\');
+ const QString longPath = QFSFileEnginePrivate::longFileName(path);
#ifndef Q_OS_WINRT
- DWORD fileAttrib = ::GetFileAttributes((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16());
+ DWORD fileAttrib = ::GetFileAttributes(reinterpret_cast<const wchar_t*>(longPath.utf16()));
#else // Q_OS_WINRT
DWORD fileAttrib = INVALID_FILE_ATTRIBUTES;
WIN32_FILE_ATTRIBUTE_DATA data;
- if (::GetFileAttributesEx((const wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), GetFileExInfoStandard, &data))
+ if (::GetFileAttributesEx(reinterpret_cast<const wchar_t*>(longPath.utf16()),
+ GetFileExInfoStandard, &data)) {
fileAttrib = data.dwFileAttributes;
+ }
#endif // Q_OS_WINRT
if (fileAttrib == INVALID_FILE_ATTRIBUTES) {
int errorCode = GetLastError();
if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) {
WIN32_FIND_DATA findData;
- if (getFindData(QFSFileEnginePrivate::longFileName(path), findData))
+ if (getFindData(longPath, findData))
fileAttrib = findData.dwFileAttributes;
}
}
@@ -1411,7 +1415,7 @@ bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Per
if (mode == 0) // not supported
return false;
- bool ret = (::_wchmod((wchar_t*)entry.nativeFilePath().utf16(), mode) == 0);
+ bool ret = ::_wchmod(reinterpret_cast<const wchar_t*>(entry.nativeFilePath().utf16()), mode) == 0;
if(!ret)
error = QSystemError(errno, QSystemError::StandardLibraryError);
return ret;
diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp
index 1134c6bb85..391d2a49af 100644
--- a/src/corelib/io/qsettings.cpp
+++ b/src/corelib/io/qsettings.cpp
@@ -77,6 +77,10 @@
# include <ioLib.h>
#endif
+#ifdef Q_OS_WASM
+#include <emscripten.h>
+#endif
+
#include <algorithm>
#include <stdlib.h>
@@ -1544,6 +1548,13 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
perms |= QFile::ReadGroup | QFile::ReadOther;
QFile(confFile->name).setPermissions(perms);
}
+#ifdef Q_OS_WASM
+ EM_ASM(
+ // Sync sandbox filesystem to persistent database filesystem. See QTBUG-70002
+ FS.syncfs(false, function(err) {
+ });
+ );
+#endif
} else {
setStatus(QSettings::AccessError);
}
diff --git a/src/corelib/io/qsettings_win.cpp b/src/corelib/io/qsettings_win.cpp
index 43e1411c76..e1922674ef 100644
--- a/src/corelib/io/qsettings_win.cpp
+++ b/src/corelib/io/qsettings_win.cpp
@@ -515,7 +515,7 @@ bool QWinSettingsPrivate::readKey(HKEY parentHandle, const QString &rSubKey, QVa
case REG_SZ: {
QString s;
if (dataSize) {
- s = QString::fromWCharArray(((const wchar_t *)data.constData()));
+ s = QString::fromWCharArray(reinterpret_cast<const wchar_t *>(data.constData()));
}
if (value != 0)
*value = stringToVariant(s);
@@ -527,7 +527,7 @@ bool QWinSettingsPrivate::readKey(HKEY parentHandle, const QString &rSubKey, QVa
if (dataSize) {
int i = 0;
for (;;) {
- QString s = QString::fromWCharArray((const wchar_t *)data.constData() + i);
+ QString s = QString::fromWCharArray(reinterpret_cast<const wchar_t *>(data.constData()) + i);
i += s.length() + 1;
if (s.isEmpty())
@@ -544,7 +544,7 @@ bool QWinSettingsPrivate::readKey(HKEY parentHandle, const QString &rSubKey, QVa
case REG_BINARY: {
QString s;
if (dataSize) {
- s = QString::fromWCharArray((const wchar_t *)data.constData(), data.size() / 2);
+ s = QString::fromWCharArray(reinterpret_cast<const wchar_t *>(data.constData()), data.size() / 2);
}
if (value != 0)
*value = stringToVariant(s);
@@ -555,7 +555,7 @@ bool QWinSettingsPrivate::readKey(HKEY parentHandle, const QString &rSubKey, QVa
case REG_DWORD: {
Q_ASSERT(data.size() == sizeof(int));
int i;
- memcpy((char*)&i, data.constData(), sizeof(int));
+ memcpy(reinterpret_cast<char*>(&i), data.constData(), sizeof(int));
if (value != 0)
*value = i;
break;
@@ -564,7 +564,7 @@ bool QWinSettingsPrivate::readKey(HKEY parentHandle, const QString &rSubKey, QVa
case REG_QWORD: {
Q_ASSERT(data.size() == sizeof(qint64));
qint64 i;
- memcpy((char*)&i, data.constData(), sizeof(qint64));
+ memcpy(reinterpret_cast<char*>(&i), data.constData(), sizeof(qint64));
if (value != 0)
*value = i;
break;
@@ -688,12 +688,12 @@ void QWinSettingsPrivate::set(const QString &uKey, const QVariant &value)
if (type == REG_BINARY) {
QString s = variantToString(value);
- regValueBuff = QByteArray((const char*)s.utf16(), s.length() * 2);
+ regValueBuff = QByteArray(reinterpret_cast<const char*>(s.utf16()), s.length() * 2);
} else {
QStringList::const_iterator it = l.constBegin();
for (; it != l.constEnd(); ++it) {
const QString &s = *it;
- regValueBuff += QByteArray((const char*)s.utf16(), (s.length() + 1) * 2);
+ regValueBuff += QByteArray(reinterpret_cast<const char*>(s.utf16()), (s.length() + 1) * 2);
}
regValueBuff.append((char)0);
regValueBuff.append((char)0);
@@ -705,7 +705,7 @@ void QWinSettingsPrivate::set(const QString &uKey, const QVariant &value)
case QVariant::UInt: {
type = REG_DWORD;
qint32 i = value.toInt();
- regValueBuff = QByteArray((const char*)&i, sizeof(qint32));
+ regValueBuff = QByteArray(reinterpret_cast<const char*>(&i), sizeof(qint32));
break;
}
@@ -713,7 +713,7 @@ void QWinSettingsPrivate::set(const QString &uKey, const QVariant &value)
case QVariant::ULongLong: {
type = REG_QWORD;
qint64 i = value.toLongLong();
- regValueBuff = QByteArray((const char*)&i, sizeof(qint64));
+ regValueBuff = QByteArray(reinterpret_cast<const char*>(&i), sizeof(qint64));
break;
}
@@ -725,11 +725,11 @@ void QWinSettingsPrivate::set(const QString &uKey, const QVariant &value)
// string type. Otherwise we use REG_BINARY.
QString s = variantToString(value);
type = s.contains(QChar::Null) ? REG_BINARY : REG_SZ;
- if (type == REG_BINARY) {
- regValueBuff = QByteArray((const char*)s.utf16(), s.length() * 2);
- } else {
- regValueBuff = QByteArray((const char*)s.utf16(), (s.length() + 1) * 2);
- }
+ int length = s.length();
+ if (type == REG_SZ)
+ ++length;
+ regValueBuff = QByteArray(reinterpret_cast<const char *>(s.utf16()),
+ int(sizeof(wchar_t)) * length);
break;
}
}
diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h
index 8f2714aa12..b14a494296 100644
--- a/src/corelib/kernel/qcore_mac_p.h
+++ b/src/corelib/kernel/qcore_mac_p.h
@@ -59,36 +59,6 @@
// --------------------------------------------------------------------------
-#if !defined(QT_BOOTSTRAPPED) && (QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_12) || !defined(Q_OS_MACOS))
-#define QT_USE_APPLE_ACTIVITIES
-
-#if defined(OS_ACTIVITY_OBJECT_API)
-#error The file <os/activity.h> has already been included
-#endif
-
-// We runtime-check all use of the activity APIs, so we can safely build
-// with them included, even if the deployment target is macOS 10.11
-#if QT_MACOS_DEPLOYMENT_TARGET_BELOW(__MAC_10_12)
-#undef __MAC_OS_X_VERSION_MIN_REQUIRED
-#define __MAC_OS_X_VERSION_MIN_REQUIRED __MAC_10_12
-#define DID_OVERRIDE_DEPLOYMENT_TARGET
-#endif
-
-#include <os/activity.h>
-#if !OS_ACTIVITY_OBJECT_API
-#error "Expected activity API to be available"
-#endif
-
-#if defined(DID_OVERRIDE_DEPLOYMENT_TARGET)
-#undef __MAC_OS_X_VERSION_MIN_REQUIRED
-#define __MAC_OS_X_VERSION_MIN_REQUIRED __MAC_10_11
-#undef DID_OVERRIDE_DEPLOYMENT_TARGET
-#endif
-
-#endif
-
-// --------------------------------------------------------------------------
-
#if defined(QT_BOOTSTRAPPED)
#include <ApplicationServices/ApplicationServices.h>
#else
@@ -220,41 +190,31 @@ Q_CORE_EXPORT AppleApplication *qt_apple_sharedApplication();
// --------------------------------------------------------------------------
-#if !defined(QT_BOOTSTRAPPED) && (QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_12) || !defined(Q_OS_MACOS))
+#if !defined(QT_BOOTSTRAPPED)
#define QT_USE_APPLE_UNIFIED_LOGGING
QT_END_NAMESPACE
#include <os/log.h>
-
-// The compiler isn't smart enough to realize that we're calling these functions
-// guarded by __builtin_available, so we need to also tag each function with the
-// runtime requirements.
-#include <os/availability.h>
-#define OS_LOG_AVAILABILITY API_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0))
QT_BEGIN_NAMESPACE
class Q_CORE_EXPORT AppleUnifiedLogger
{
public:
static bool messageHandler(QtMsgType msgType, const QMessageLogContext &context, const QString &message,
- const QString &subsystem = QString()) OS_LOG_AVAILABILITY;
+ const QString &subsystem = QString());
private:
- static os_log_type_t logTypeForMessageType(QtMsgType msgType) OS_LOG_AVAILABILITY;
- static os_log_t cachedLog(const QString &subsystem, const QString &category) OS_LOG_AVAILABILITY;
+ static os_log_type_t logTypeForMessageType(QtMsgType msgType);
+ static os_log_t cachedLog(const QString &subsystem, const QString &category);
};
-#undef OS_LOG_AVAILABILITY
-
#endif
// --------------------------------------------------------------------------
-#if defined(QT_USE_APPLE_ACTIVITIES)
+#if !defined(QT_BOOTSTRAPPED)
QT_END_NAMESPACE
-#include <os/availability.h>
-#define OS_ACTIVITY_AVAILABILITY API_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0))
-#define OS_ACTIVITY_AVAILABILITY_CHECK __builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *)
+#include <os/activity.h>
QT_BEGIN_NAMESPACE
template <typename T> using QAppleOsType = QAppleRefCounted<T, void *, os_retain, os_release>;
@@ -263,7 +223,7 @@ class Q_CORE_EXPORT QAppleLogActivity
{
public:
QAppleLogActivity() : activity(nullptr) {}
- QAppleLogActivity(os_activity_t activity) OS_ACTIVITY_AVAILABILITY : activity(activity) {}
+ QAppleLogActivity(os_activity_t activity) : activity(activity) {}
~QAppleLogActivity() { if (activity) leave(); }
QAppleLogActivity(const QAppleLogActivity &) = delete;
@@ -284,21 +244,17 @@ public:
QAppleLogActivity&& enter()
{
- if (activity) {
- if (OS_ACTIVITY_AVAILABILITY_CHECK)
- os_activity_scope_enter(static_cast<os_activity_t>(*this), &state);
- }
+ if (activity)
+ os_activity_scope_enter(static_cast<os_activity_t>(*this), &state);
return std::move(*this);
}
void leave() {
- if (activity) {
- if (OS_ACTIVITY_AVAILABILITY_CHECK)
- os_activity_scope_leave(&state);
- }
+ if (activity)
+ os_activity_scope_leave(&state);
}
- operator os_activity_t() OS_ACTIVITY_AVAILABILITY
+ operator os_activity_t()
{
return reinterpret_cast<os_activity_t>(static_cast<void *>(activity));
}
@@ -312,9 +268,7 @@ private:
#define QT_APPLE_LOG_ACTIVITY_CREATE(condition, description, parent) []() { \
if (!(condition)) \
return QAppleLogActivity(); \
- if (OS_ACTIVITY_AVAILABILITY_CHECK) \
- return QAppleLogActivity(os_activity_create(description, parent, OS_ACTIVITY_FLAG_DEFAULT)); \
- return QAppleLogActivity(); \
+ return QAppleLogActivity(os_activity_create(description, parent, OS_ACTIVITY_FLAG_DEFAULT)); \
}()
#define QT_VA_ARGS_CHOOSE(_1, _2, _3, _4, _5, _6, _7, _8, _9, N, ...) N
@@ -335,12 +289,7 @@ QT_MAC_WEAK_IMPORT(_os_activity_current);
#define QT_APPLE_SCOPED_LOG_ACTIVITY(...) QAppleLogActivity scopedLogActivity = QT_APPLE_LOG_ACTIVITY(__VA_ARGS__).enter();
-#else
-// No-ops for macOS 10.11. We don't need to provide QT_APPLE_SCOPED_LOG_ACTIVITY,
-// as all the call sites for that are in code that's only built on 10.12 and above.
-#define QT_APPLE_LOG_ACTIVITY_WITH_PARENT(...)
-#define QT_APPLE_LOG_ACTIVITY(...)
-#endif // QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE
+#endif // !defined(QT_BOOTSTRAPPED)
// -------------------------------------------------------------------------
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index 0303916c11..1350a7aa94 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -118,6 +118,10 @@
# include <taskLib.h>
#endif
+#ifdef Q_OS_WASM
+#include <emscripten.h>
+#endif
+
#ifdef QT_BOOTSTRAPPED
#include <private/qtrace_p.h>
#else
@@ -486,6 +490,13 @@ QCoreApplicationPrivate::QCoreApplicationPrivate(int &aargc, char **aargv, uint
QCoreApplicationPrivate::~QCoreApplicationPrivate()
{
+#ifdef Q_OS_WASM
+ EM_ASM(
+ // unmount persistent directory as IDBFS
+ // see also QTBUG-70002
+ FS.unmount('/home/web_user');
+ );
+#endif
#ifndef QT_NO_QOBJECT
cleanupThreadData();
#endif
@@ -777,6 +788,17 @@ void QCoreApplicationPrivate::init()
Q_ASSERT_X(!QCoreApplication::self, "QCoreApplication", "there should be only one application object");
QCoreApplication::self = q;
+#ifdef Q_OS_WASM
+ EM_ASM(
+ // mount and sync persistent filesystem to sandbox
+ FS.mount(IDBFS, {}, '/home/web_user');
+ FS.syncfs(true, function(err) {
+ if (err)
+ Module.print(err);
+ });
+ );
+#endif
+
// Store app name/version (so they're still available after QCoreApplication is destroyed)
if (!coreappdata()->applicationNameSet)
coreappdata()->application = appName();
diff --git a/src/corelib/kernel/qeventdispatcher_unix.cpp b/src/corelib/kernel/qeventdispatcher_unix.cpp
index a28f2e3f0a..535f86fefe 100644
--- a/src/corelib/kernel/qeventdispatcher_unix.cpp
+++ b/src/corelib/kernel/qeventdispatcher_unix.cpp
@@ -130,7 +130,7 @@ static void initThreadPipeFD(int fd)
bool QThreadPipe::init()
{
-#if defined(Q_OS_NACL)
+#if defined(Q_OS_NACL) || defined(Q_OS_WASM)
// do nothing.
#elif defined(Q_OS_VXWORKS)
qsnprintf(name, sizeof(name), "/pipe/qt_%08x", int(taskIdSelf()));
diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp
index f1a4088d98..2862f42b2b 100644
--- a/src/corelib/kernel/qeventdispatcher_win.cpp
+++ b/src/corelib/kernel/qeventdispatcher_win.cpp
@@ -120,7 +120,7 @@ void WINAPI QT_WIN_CALLBACK qt_fast_timer_proc(uint timerId, uint /*reserved*/,
{
if (!timerId) // sanity check
return;
- WinTimerInfo *t = (WinTimerInfo*)user;
+ auto t = reinterpret_cast<WinTimerInfo*>(user);
Q_ASSERT(t);
QCoreApplication::postEvent(t->dispatcher, new QTimerEvent(t->timerId));
}
@@ -146,9 +146,9 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
}
#ifdef GWLP_USERDATA
- QEventDispatcherWin32 *q = (QEventDispatcherWin32 *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ auto q = reinterpret_cast<QEventDispatcherWin32 *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
#else
- QEventDispatcherWin32 *q = (QEventDispatcherWin32 *) GetWindowLong(hwnd, GWL_USERDATA);
+ auto q = reinterpret_cast<QEventDispatcherWin32 *>(GetWindowLong(hwnd, GWL_USERDATA));
#endif
QEventDispatcherWin32Private *d = 0;
if (q != 0)
@@ -369,9 +369,9 @@ static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatch
}
#ifdef GWLP_USERDATA
- SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)eventDispatcher);
+ SetWindowLongPtr(wnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(eventDispatcher));
#else
- SetWindowLong(wnd, GWL_USERDATA, (LONG)eventDispatcher);
+ SetWindowLong(wnd, GWL_USERDATA, reinterpret_cast<LONG>(eventDispatcher));
#endif
return wnd;
@@ -603,7 +603,7 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
if (haveMessage) {
// WinCE doesn't support hooks at all, so we have to call this by hand :(
if (!d->getMessageHook)
- (void) qt_GetMessageHook(0, PM_REMOVE, (LPARAM) &msg);
+ (void) qt_GetMessageHook(0, PM_REMOVE, reinterpret_cast<LPARAM>(&msg));
if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) {
if (seenWM_QT_SENDPOSTEDEVENTS) {
diff --git a/src/corelib/kernel/qeventloop.cpp b/src/corelib/kernel/qeventloop.cpp
index f1d32b15d1..a6cc51621a 100644
--- a/src/corelib/kernel/qeventloop.cpp
+++ b/src/corelib/kernel/qeventloop.cpp
@@ -48,6 +48,10 @@
#include "qeventloop_p.h"
#include <private/qthread_p.h>
+#ifdef Q_OS_WASM
+#include <emscripten.h>
+#endif
+
QT_BEGIN_NAMESPACE
/*!
@@ -208,6 +212,15 @@ int QEventLoop::exec(ProcessEventsFlags flags)
if (app && app->thread() == thread())
QCoreApplication::removePostedEvents(app, QEvent::Quit);
+#ifdef Q_OS_WASM
+ // Partial support for nested event loops: Make the runtime throw a JavaSrcript
+ // exception, which returns control to the browser while preserving the C++ stack.
+ // Event processing then continues as normal. The sleep call below never returns.
+ // QTBUG-70185
+ if (d->threadData->loopLevel > 1)
+ emscripten_sleep(1);
+#endif
+
while (!d->exit.loadAcquire())
processEvents(flags | WaitForMoreEvents | EventLoopExec);
@@ -269,6 +282,17 @@ void QEventLoop::exit(int returnCode)
d->returnCode.store(returnCode);
d->exit.storeRelease(true);
d->threadData->eventDispatcher.load()->interrupt();
+
+#ifdef Q_OS_WASM
+ // QEventLoop::exec() never returns in emscripten. We implement approximate behavior here.
+ // QTBUG-70185
+ if (d->threadData->loopLevel == 1) {
+ emscripten_force_exit(returnCode);
+ } else {
+ d->inExec = false;
+ --d->threadData->loopLevel;
+ }
+#endif
}
/*!
diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h
index 4df9a8de77..522bd78e42 100644
--- a/src/corelib/kernel/qmetaobject_p.h
+++ b/src/corelib/kernel/qmetaobject_p.h
@@ -60,6 +60,8 @@
#include <QtCore/qvarlengtharray.h>
QT_BEGIN_NAMESPACE
+// ### TODO Qt6: add a proper namespace with Q_NAMESPACE and use scoped enums
+// A namespace and scoped are needed to avoid enum clashes
enum PropertyFlags {
Invalid = 0x00000000,
@@ -103,7 +105,7 @@ enum MethodFlags {
MethodRevisioned = 0x80
};
-enum MetaObjectFlags {
+enum MetaObjectFlags { // keep it in sync with QMetaObjectBuilder::MetaObjectFlag enum
DynamicMetaObject = 0x01,
RequiresVariantMetaObject = 0x02,
PropertyAccessInStaticMetaCall = 0x04 // since Qt 5.5, property code is in the static metacall
diff --git a/src/corelib/kernel/qmetaobjectbuilder_p.h b/src/corelib/kernel/qmetaobjectbuilder_p.h
index 781d206e0b..115ec835aa 100644
--- a/src/corelib/kernel/qmetaobjectbuilder_p.h
+++ b/src/corelib/kernel/qmetaobjectbuilder_p.h
@@ -93,8 +93,11 @@ public:
};
Q_DECLARE_FLAGS(AddMembers, AddMember)
- enum MetaObjectFlag {
- DynamicMetaObject = 0x01
+ // ### TODO Qt6: remove me and use the MetaObjectFlags enum from qmetaobject_p.h
+ enum MetaObjectFlag { // keep it in sync with enum MetaObjectFlags from qmetaobject_p.h
+ DynamicMetaObject = 0x01,
+ RequiresVariantMetaObject = 0x02,
+ PropertyAccessInStaticMetaCall = 0x04 // since Qt 5.5, property code is in the static metacall
};
Q_DECLARE_FLAGS(MetaObjectFlags, MetaObjectFlag)
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 76e3d0d014..82952919dd 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -1054,45 +1054,40 @@ int QMetaType::registerType(const char *typeName, Deleter deleter,
return registerNormalizedType(normalizedTypeName, deleter, creator, destructor, constructor, size, flags, metaObject);
}
-
/*!
- \internal
- \since 5.0
- \overload
- Don't use, kept for binary compatibility
+ \internal
+ \since 5.12
- ### TODO Qt6: remove me
-*/
-int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName, Deleter deleter,
- Creator creator,
- Destructor destructor,
- Constructor constructor,
- int size, TypeFlags flags, const QMetaObject *metaObject)
+ Registers a user type for marshalling, with \a typeName, a \a
+ \a destructor, a \a constructor, and a \a size. Returns the
+ type's handle, or -1 if the type could not be registered.
+ */
+int QMetaType::registerType(const char *typeName,
+ TypedDestructor destructor,
+ TypedConstructor constructor,
+ int size,
+ TypeFlags flags,
+ const QMetaObject *metaObject)
{
- Q_UNUSED(deleter);
- Q_UNUSED(creator);
+#ifdef QT_NO_QOBJECT
+ NS(QByteArray) normalizedTypeName = typeName;
+#else
+ NS(QByteArray) normalizedTypeName = QMetaObject::normalizedType(typeName);
+#endif
+
return registerNormalizedType(normalizedTypeName, destructor, constructor, size, flags, metaObject);
}
-/*!
- \internal
- \since 5.5
-
- Registers a user type for marshalling, with \a normalizedTypeName,
- a \a destructor, a \a constructor, and a \a size. Returns the type's
- handle, or -1 if the type could not be registered.
-
- \note normalizedTypeName is not checked for conformance with
- Qt's normalized format, so it must already conform.
- */
-int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName,
- Destructor destructor,
- Constructor constructor,
- int size, TypeFlags flags, const QMetaObject *metaObject)
+static int registerNormalizedType(const NS(QByteArray) &normalizedTypeName,
+ QMetaType::Destructor destructor,
+ QMetaType::Constructor constructor,
+ QMetaType::TypedDestructor typedDestructor,
+ QMetaType::TypedConstructor typedConstructor,
+ int size, QMetaType::TypeFlags flags, const QMetaObject *metaObject)
{
QVector<QCustomTypeInfo> *ct = customTypes();
- if (!ct || normalizedTypeName.isEmpty() || !destructor || !constructor)
+ if (!ct || normalizedTypeName.isEmpty() || (!destructor && !typedDestructor) || (!constructor && !typedConstructor))
return -1;
int idx = qMetaTypeStaticType(normalizedTypeName.constData(),
@@ -1100,13 +1095,13 @@ int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName,
int previousSize = 0;
QMetaType::TypeFlags::Int previousFlags = 0;
- if (idx == UnknownType) {
+ if (idx == QMetaType::UnknownType) {
QWriteLocker locker(customTypesLock());
int posInVector = -1;
idx = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(),
normalizedTypeName.size(),
&posInVector);
- if (idx == UnknownType) {
+ if (idx == QMetaType::UnknownType) {
QCustomTypeInfo inf;
inf.typeName = normalizedTypeName;
#ifndef QT_NO_DATASTREAM
@@ -1114,30 +1109,32 @@ int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName,
inf.saveOp = 0;
#endif
inf.alias = -1;
+ inf.typedConstructor = typedConstructor;
+ inf.typedDestructor = typedDestructor;
inf.constructor = constructor;
inf.destructor = destructor;
inf.size = size;
inf.flags = flags;
inf.metaObject = metaObject;
if (posInVector == -1) {
- idx = ct->size() + User;
+ idx = ct->size() + QMetaType::User;
ct->append(inf);
} else {
- idx = posInVector + User;
+ idx = posInVector + QMetaType::User;
ct->data()[posInVector] = inf;
}
return idx;
}
- if (idx >= User) {
- previousSize = ct->at(idx - User).size;
- previousFlags = ct->at(idx - User).flags;
+ if (idx >= QMetaType::User) {
+ previousSize = ct->at(idx - QMetaType::User).size;
+ previousFlags = ct->at(idx - QMetaType::User).flags;
// Set new/additional flags in case of old library/app.
// Ensures that older code works in conjunction with new Qt releases
// requiring the new flags.
if (flags != previousFlags) {
- QCustomTypeInfo &inf = ct->data()[idx - User];
+ QCustomTypeInfo &inf = ct->data()[idx - QMetaType::User];
inf.flags |= flags;
if (metaObject)
inf.metaObject = metaObject;
@@ -1145,7 +1142,7 @@ int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName,
}
}
- if (idx < User) {
+ if (idx < QMetaType::User) {
previousSize = QMetaType::sizeOf(idx);
previousFlags = QMetaType::typeFlags(idx);
}
@@ -1158,8 +1155,8 @@ int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName,
}
// these flags cannot change in a binary compatible way:
- const int binaryCompatibilityFlag = PointerToQObject | IsEnumeration | SharedPointerToQObject
- | WeakPointerToQObject | TrackingPointerToQObject;
+ const int binaryCompatibilityFlag = QMetaType::PointerToQObject | QMetaType::IsEnumeration | QMetaType::SharedPointerToQObject
+ | QMetaType::WeakPointerToQObject | QMetaType::TrackingPointerToQObject;
if (Q_UNLIKELY((previousFlags ^ flags) & binaryCompatibilityFlag)) {
const char *msg = "QMetaType::registerType: Binary compatibility break. "
@@ -1173,6 +1170,66 @@ int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName,
}
/*!
+ \internal
+ \since 5.0
+ \overload
+ Don't use, kept for binary compatibility
+
+ ### TODO Qt6: remove me
+*/
+int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName, Deleter deleter,
+ Creator creator,
+ Destructor destructor,
+ Constructor constructor,
+ int size, TypeFlags flags, const QMetaObject *metaObject)
+{
+ Q_UNUSED(deleter);
+ Q_UNUSED(creator);
+ return registerNormalizedType(normalizedTypeName, destructor, constructor, size, flags, metaObject);
+}
+
+
+/*!
+ \internal
+ \since 5.5
+
+ Registers a user type for marshalling, with \a normalizedTypeName,
+ a \a destructor, a \a constructor, and a \a size. Returns the type's
+ handle, or -1 if the type could not be registered.
+
+ \note normalizedTypeName is not checked for conformance with
+ Qt's normalized format, so it must already conform.
+
+ ### TODO Qt6: remove me
+ */
+int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName,
+ Destructor destructor,
+ Constructor constructor,
+ int size, TypeFlags flags, const QMetaObject *metaObject)
+{
+ return NS(registerNormalizedType)(normalizedTypeName, destructor, constructor, nullptr, nullptr, size, flags, metaObject);
+}
+
+/*!
+ \internal
+ \since 5.12
+
+ Registers a user type for marshalling, with \a normalizedTypeName,
+ a \a destructor, a \a constructor, and a \a size. Returns the type's
+ handle, or -1 if the type could not be registered.
+
+ \note normalizedTypeName is not checked for conformance with
+ Qt's normalized format, so it must already conform.
+ */
+int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName,
+ TypedDestructor destructor,
+ TypedConstructor constructor,
+ int size, TypeFlags flags, const QMetaObject *metaObject)
+{
+ return NS(registerNormalizedType)(normalizedTypeName, nullptr, nullptr, destructor, constructor, size, flags, metaObject);
+}
+
+/*!
\internal
\since 4.7
@@ -1850,14 +1907,19 @@ private:
static void *customTypeConstructor(const int type, void *where, const void *copy)
{
QMetaType::Constructor ctor;
+ QMetaType::TypedConstructor tctor;
const QVector<QCustomTypeInfo> * const ct = customTypes();
{
QReadLocker locker(customTypesLock());
if (Q_UNLIKELY(type < QMetaType::User || !ct || ct->count() <= type - QMetaType::User))
return 0;
- ctor = ct->at(type - QMetaType::User).constructor;
+ const auto &typeInfo = ct->at(type - QMetaType::User);
+ ctor = typeInfo.constructor;
+ tctor = typeInfo.typedConstructor;
}
- Q_ASSERT_X(ctor, "void *QMetaType::construct(int type, void *where, const void *copy)", "The type was not properly registered");
+ Q_ASSERT_X((ctor || tctor) , "void *QMetaType::construct(int type, void *where, const void *copy)", "The type was not properly registered");
+ if (Q_UNLIKELY(tctor))
+ return tctor(type, where, copy);
return ctor(where, copy);
}
@@ -1943,14 +2005,19 @@ private:
static void customTypeDestructor(const int type, void *where)
{
QMetaType::Destructor dtor;
+ QMetaType::TypedDestructor tdtor;
const QVector<QCustomTypeInfo> * const ct = customTypes();
{
QReadLocker locker(customTypesLock());
if (Q_UNLIKELY(type < QMetaType::User || !ct || ct->count() <= type - QMetaType::User))
return;
- dtor = ct->at(type - QMetaType::User).destructor;
+ const auto &typeInfo = ct->at(type - QMetaType::User);
+ dtor = typeInfo.destructor;
+ tdtor = typeInfo.typedDestructor;
}
- Q_ASSERT_X(dtor, "void QMetaType::destruct(int type, void *where)", "The type was not properly registered");
+ Q_ASSERT_X((dtor || tdtor), "void QMetaType::destruct(int type, void *where)", "The type was not properly registered");
+ if (Q_UNLIKELY(tdtor))
+ return tdtor(type, where);
dtor(where);
}
@@ -2363,10 +2430,12 @@ QMetaType QMetaType::typeInfo(const int type)
{
TypeInfo typeInfo(type);
QMetaTypeSwitcher::switcher<void>(typeInfo, type, 0);
- return typeInfo.info.constructor ? QMetaType(static_cast<ExtensionFlag>(QMetaType::CreateEx | QMetaType::DestroyEx)
- , static_cast<const QMetaTypeInterface *>(0) // typeInfo::info is a temporary variable, we can't return address of it.
- , 0 // unused
- , 0 // unused
+ return (typeInfo.info.constructor || typeInfo.info.typedConstructor)
+ ? QMetaType(static_cast<ExtensionFlag>(QMetaType::CreateEx | QMetaType::DestroyEx |
+ (typeInfo.info.typedConstructor ? QMetaType::ConstructEx | QMetaType::DestructEx : 0))
+ , static_cast<const QMetaTypeInterface *>(nullptr) // typeInfo::info is a temporary variable, we can't return address of it.
+ , typeInfo.info.typedConstructor
+ , typeInfo.info.typedDestructor
, typeInfo.info.saveOp
, typeInfo.info.loadOp
, typeInfo.info.constructor
@@ -2408,8 +2477,8 @@ QMetaType::QMetaType(const int typeId)
Copy constructs a QMetaType object.
*/
QMetaType::QMetaType(const QMetaType &other)
- : m_creator_unused(other.m_creator_unused)
- , m_deleter_unused(other.m_deleter_unused)
+ : m_typedConstructor(other.m_typedConstructor)
+ , m_typedDestructor(other.m_typedDestructor)
, m_saveOp(other.m_saveOp)
, m_loadOp(other.m_loadOp)
, m_constructor(other.m_constructor)
@@ -2424,8 +2493,8 @@ QMetaType::QMetaType(const QMetaType &other)
QMetaType &QMetaType::operator =(const QMetaType &other)
{
- m_creator_unused = other.m_creator_unused;
- m_deleter_unused = other.m_deleter_unused;
+ m_typedConstructor = other.m_typedConstructor;
+ m_typedDestructor = other.m_typedDestructor;
m_saveOp = other.m_saveOp;
m_loadOp = other.m_loadOp;
m_constructor = other.m_constructor;
@@ -2481,6 +2550,8 @@ void *QMetaType::createExtended(const void *copy) const
{
if (m_typeId == QMetaType::UnknownType)
return 0;
+ if (Q_UNLIKELY(m_typedConstructor && !m_constructor))
+ return m_typedConstructor(m_typeId, operator new(m_size), copy);
return m_constructor(operator new(m_size), copy);
}
@@ -2495,7 +2566,10 @@ void *QMetaType::createExtended(const void *copy) const
*/
void QMetaType::destroyExtended(void *data) const
{
- m_destructor(data);
+ if (Q_UNLIKELY(m_typedDestructor && !m_destructor))
+ m_typedDestructor(m_typeId, data);
+ else
+ m_destructor(data);
operator delete(data);
}
@@ -2508,9 +2582,9 @@ void QMetaType::destroyExtended(void *data) const
*/
void *QMetaType::constructExtended(void *where, const void *copy) const
{
- Q_UNUSED(where);
- Q_UNUSED(copy);
- return 0;
+ if (m_typedConstructor && !m_constructor)
+ return m_typedConstructor(m_typeId, where, copy);
+ return nullptr;
}
/*!
@@ -2522,7 +2596,8 @@ void *QMetaType::constructExtended(void *where, const void *copy) const
*/
void QMetaType::destructExtended(void *data) const
{
- Q_UNUSED(data);
+ if (m_typedDestructor && !m_destructor)
+ m_typedDestructor(m_typeId, data);
}
/*!
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index 48cbe7f00b..ed7feee775 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -493,8 +493,12 @@ public:
typedef void (*Deleter)(void *);
typedef void *(*Creator)(const void *);
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
typedef void (*Destructor)(void *);
- typedef void *(*Constructor)(void *, const void *);
+ typedef void *(*Constructor)(void *, const void *); // TODO Qt6: remove me
+#endif
+ typedef void (*TypedDestructor)(int, void *);
+ typedef void *(*TypedConstructor)(int, void *, const void *);
typedef void (*SaveOperator)(QDataStream &, const void *);
typedef void (*LoadOperator)(QDataStream &, void *);
@@ -513,6 +517,12 @@ public:
int size,
QMetaType::TypeFlags flags,
const QMetaObject *metaObject);
+ static int registerType(const char *typeName,
+ TypedDestructor destructor,
+ TypedConstructor constructor,
+ int size,
+ QMetaType::TypeFlags flags,
+ const QMetaObject *metaObject);
static bool unregisterType(int type);
static int registerNormalizedType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName, Deleter deleter,
Creator creator,
@@ -526,6 +536,11 @@ public:
int size,
QMetaType::TypeFlags flags,
const QMetaObject *metaObject);
+ static int registerNormalizedType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName, TypedDestructor destructor,
+ TypedConstructor constructor,
+ int size,
+ QMetaType::TypeFlags flags,
+ const QMetaObject *metaObject);
static int registerTypedef(const char *typeName, int aliasId);
static int registerNormalizedTypedef(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName, int aliasId);
static int type(const char *typeName);
@@ -683,8 +698,8 @@ public:
private:
static QMetaType typeInfo(const int type);
inline QMetaType(const ExtensionFlag extensionFlags, const QMetaTypeInterface *info,
- Creator creator,
- Deleter deleter,
+ TypedConstructor creator,
+ TypedDestructor deleter,
SaveOperator saveOp,
LoadOperator loadOp,
Constructor constructor,
@@ -731,8 +746,8 @@ public:
static void unregisterConverterFunction(int from, int to);
private:
- Creator m_creator_unused;
- Deleter m_deleter_unused;
+ TypedConstructor m_typedConstructor;
+ TypedDestructor m_typedDestructor;
SaveOperator m_saveOp;
LoadOperator m_loadOp;
Constructor m_constructor;
@@ -2163,8 +2178,8 @@ QT_BEGIN_NAMESPACE
#undef Q_DECLARE_METATYPE_TEMPLATE_SMART_POINTER_ITER
inline QMetaType::QMetaType(const ExtensionFlag extensionFlags, const QMetaTypeInterface *info,
- Creator creator,
- Deleter deleter,
+ TypedConstructor creator,
+ TypedDestructor deleter,
SaveOperator saveOp,
LoadOperator loadOp,
Constructor constructor,
@@ -2173,8 +2188,8 @@ inline QMetaType::QMetaType(const ExtensionFlag extensionFlags, const QMetaTypeI
uint theTypeFlags,
int typeId,
const QMetaObject *_metaObject)
- : m_creator_unused(creator)
- , m_deleter_unused(deleter)
+ : m_typedConstructor(creator)
+ , m_typedDestructor(deleter)
, m_saveOp(saveOp)
, m_loadOp(loadOp)
, m_constructor(constructor)
diff --git a/src/corelib/kernel/qmetatype_p.h b/src/corelib/kernel/qmetatype_p.h
index 76f43db8d7..94e9228778 100644
--- a/src/corelib/kernel/qmetatype_p.h
+++ b/src/corelib/kernel/qmetatype_p.h
@@ -126,11 +126,13 @@ class QMetaTypeInterface
public:
QMetaType::SaveOperator saveOp;
QMetaType::LoadOperator loadOp;
- QMetaType::Constructor constructor;
+ QMetaType::Constructor constructor; // TODO Qt6: remove me
QMetaType::Destructor destructor;
int size;
QMetaType::TypeFlags::Int flags;
const QMetaObject *metaObject;
+ QMetaType::TypedConstructor typedConstructor;
+ QMetaType::TypedDestructor typedDestructor;
};
#ifndef QT_NO_DATASTREAM
@@ -161,7 +163,9 @@ public:
/*destructor*/(QtMetaTypePrivate::QMetaTypeFunctionHelper<Type, QtMetaTypePrivate::TypeDefinition<Type>::IsAvailable>::Destruct), \
/*size*/(QTypeInfo<Type>::sizeOf), \
/*flags*/QtPrivate::QMetaTypeTypeFlags<Type>::Flags, \
- /*metaObject*/METAOBJECT_DELEGATE(Type) \
+ /*metaObject*/METAOBJECT_DELEGATE(Type), \
+ /*typedConstructor*/ nullptr, \
+ /*typedDestructor*/ nullptr \
}
@@ -184,7 +188,9 @@ public:
/*destructor*/ 0, \
/*size*/ 0, \
/*flags*/ 0, \
- /*metaObject*/ 0 \
+ /*metaObject*/ 0 , \
+ /*typedConstructor*/ nullptr, \
+ /*typedDestructor*/ nullptr \
}
namespace QtMetaTypePrivate {
diff --git a/src/corelib/kernel/qsharedmemory_win.cpp b/src/corelib/kernel/qsharedmemory_win.cpp
index be42a369c2..467398e039 100644
--- a/src/corelib/kernel/qsharedmemory_win.cpp
+++ b/src/corelib/kernel/qsharedmemory_win.cpp
@@ -101,7 +101,8 @@ HANDLE QSharedMemoryPrivate::handle()
#if defined(Q_OS_WINRT)
hand = OpenFileMappingFromApp(FILE_MAP_ALL_ACCESS, FALSE, reinterpret_cast<PCWSTR>(nativeKey.utf16()));
#else
- hand = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, (wchar_t*)nativeKey.utf16());
+ hand = OpenFileMapping(FILE_MAP_ALL_ACCESS, false,
+ reinterpret_cast<const wchar_t*>(nativeKey.utf16()));
#endif
if (!hand) {
setErrorString(function);
@@ -133,9 +134,11 @@ bool QSharedMemoryPrivate::create(int size)
// Create the file mapping.
#if defined(Q_OS_WINRT)
- hand = CreateFileMappingFromApp(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, size, (PCWSTR)nativeKey.utf16());
+ hand = CreateFileMappingFromApp(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, size,
+ reinterpret_cast<PCWSTR>(nativeKey.utf16()));
#else
- hand = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, size, (wchar_t*)nativeKey.utf16());
+ hand = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, size,
+ reinterpret_cast<const wchar_t*>(nativeKey.utf16()));
#endif
setErrorString(function);
diff --git a/src/corelib/kernel/qsystemsemaphore_win.cpp b/src/corelib/kernel/qsystemsemaphore_win.cpp
index 3395f5641e..2b35803291 100644
--- a/src/corelib/kernel/qsystemsemaphore_win.cpp
+++ b/src/corelib/kernel/qsystemsemaphore_win.cpp
@@ -86,9 +86,12 @@ HANDLE QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode)
// Create it if it doesn't already exists.
if (semaphore == 0) {
#if defined(Q_OS_WINRT)
- semaphore = CreateSemaphoreEx(0, initialValue, MAXLONG, (wchar_t*)fileName.utf16(), 0, SEMAPHORE_ALL_ACCESS);
+ semaphore = CreateSemaphoreEx(0, initialValue, MAXLONG,
+ reinterpret_cast<const wchar_t*>(fileName.utf16()),
+ 0, SEMAPHORE_ALL_ACCESS);
#else
- semaphore = CreateSemaphore(0, initialValue, MAXLONG, (wchar_t*)fileName.utf16());
+ semaphore = CreateSemaphore(0, initialValue, MAXLONG,
+ reinterpret_cast<const wchar_t*>(fileName.utf16()));
#endif
if (semaphore == NULL)
setErrorString(QLatin1String("QSystemSemaphore::handle"));
diff --git a/src/corelib/mimetypes/qmimedatabase.cpp b/src/corelib/mimetypes/qmimedatabase.cpp
index a58698af53..10b5c8eafd 100644
--- a/src/corelib/mimetypes/qmimedatabase.cpp
+++ b/src/corelib/mimetypes/qmimedatabase.cpp
@@ -151,7 +151,9 @@ void QMimeDatabasePrivate::loadProviders()
QVector<QMimeProviderBase *> QMimeDatabasePrivate::providers()
{
+#ifndef Q_OS_WASM // stub implementation always returns true
Q_ASSERT(!mutex.tryLock()); // caller should have locked mutex
+#endif
if (m_providers.isEmpty()) {
loadProviders();
m_lastCheck.start();
diff --git a/src/corelib/plugin/plugin.pri b/src/corelib/plugin/plugin.pri
index a0e0d76044..13153e8d0a 100644
--- a/src/corelib/plugin/plugin.pri
+++ b/src/corelib/plugin/plugin.pri
@@ -4,6 +4,7 @@ HEADERS += \
plugin/qfactoryinterface.h \
plugin/qpluginloader.h \
plugin/qplugin.h \
+ plugin/qplugin_p.h \
plugin/quuid.h \
plugin/qfactoryloader_p.h
diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp
index 0b35f41ca3..35c64180d4 100644
--- a/src/corelib/plugin/qfactoryloader.cpp
+++ b/src/corelib/plugin/qfactoryloader.cpp
@@ -47,9 +47,12 @@
#include <qdebug.h>
#include "qmutex.h"
#include "qplugin.h"
+#include "qplugin_p.h"
#include "qpluginloader.h"
#include "private/qobject_p.h"
#include "private/qcoreapplication_p.h"
+#include "qcbormap.h"
+#include "qcborvalue.h"
#include "qjsondocument.h"
#include "qjsonvalue.h"
#include "qjsonobject.h"
@@ -64,22 +67,86 @@ static inline int metaDataSignatureLength()
return sizeof("QTMETADATA ") - 1;
}
-QJsonDocument qJsonFromRawLibraryMetaData(const char *raw, qsizetype sectionSize)
+static QJsonDocument jsonFromCborMetaData(const char *raw, qsizetype size, QString *errMsg)
+{
+ // extract the keys not stored in CBOR
+ int qt_metadataVersion = quint8(raw[0]);
+ int qt_version = qFromBigEndian<quint16>(raw + 1);
+ int qt_archRequirements = quint8(raw[3]);
+ if (Q_UNLIKELY(raw[-1] != '!' || qt_metadataVersion != 0)) {
+ *errMsg = QStringLiteral("Invalid metadata version");
+ return QJsonDocument();
+ }
+
+ raw += 4;
+ size -= 4;
+ QByteArray ba = QByteArray::fromRawData(raw, int(size));
+ QCborParserError err;
+ QCborValue metadata = QCborValue::fromCbor(ba, &err);
+
+ if (err.error != QCborError::NoError) {
+ *errMsg = QLatin1String("Metadata parsing error: ") + err.error.toString();
+ return QJsonDocument();
+ }
+
+ if (!metadata.isMap()) {
+ *errMsg = QStringLiteral("Unexpected metadata contents");
+ return QJsonDocument();
+ }
+
+ QJsonObject o;
+ o.insert(QLatin1String("version"), qt_version << 8);
+ o.insert(QLatin1String("debug"), bool(qt_archRequirements & 1));
+ o.insert(QLatin1String("archreq"), qt_archRequirements);
+
+ // convert the top-level map integer keys
+ for (auto it : metadata.toMap()) {
+ QString key;
+ if (it.first.isInteger()) {
+ switch (it.first.toInteger()) {
+#define CONVERT_TO_STRING(IntKey, StringKey, Description) \
+ case int(IntKey): key = QStringLiteral(StringKey); break;
+ QT_PLUGIN_FOREACH_METADATA(CONVERT_TO_STRING)
+#undef CONVERT_TO_STRING
+
+ case int(QtPluginMetaDataKeys::Requirements):
+ // special case: recreate the debug key
+ o.insert(QLatin1String("debug"), bool(it.second.toInteger() & 1));
+ key = QStringLiteral("archreq");
+ break;
+ }
+ } else {
+ key = it.first.toString();
+ }
+
+ if (!key.isEmpty())
+ o.insert(key, it.second.toJsonValue());
+ }
+ return QJsonDocument(o);
+}
+
+QJsonDocument qJsonFromRawLibraryMetaData(const char *raw, qsizetype sectionSize, QString *errMsg)
{
raw += metaDataSignatureLength();
sectionSize -= metaDataSignatureLength();
- // the size of the embedded JSON object can be found 8 bytes into the data (see qjson_p.h)
- uint size = qFromLittleEndian<uint>(raw + 8);
- // but the maximum size of binary JSON is 128 MB
- size = qMin(size, 128U * 1024 * 1024);
- // and it doesn't include the size of the header (8 bytes)
- size += 8;
- // finally, it can't be bigger than the file or section size
- size = qMin(sectionSize, qsizetype(size));
-
- QByteArray json(raw, size);
- return QJsonDocument::fromBinaryData(json);
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ if (Q_UNLIKELY(raw[-1] == ' ')) {
+ // the size of the embedded JSON object can be found 8 bytes into the data (see qjson_p.h)
+ uint size = qFromLittleEndian<uint>(raw + 8);
+ // but the maximum size of binary JSON is 128 MB
+ size = qMin(size, 128U * 1024 * 1024);
+ // and it doesn't include the size of the header (8 bytes)
+ size += 8;
+ // finally, it can't be bigger than the file or section size
+ size = qMin(sectionSize, qsizetype(size));
+
+ QByteArray json(raw, size);
+ return QJsonDocument::fromBinaryData(json);
+ }
+#endif
+
+ return jsonFromCborMetaData(raw, sectionSize, errMsg);
}
class QFactoryLoaderPrivate : public QObjectPrivate
diff --git a/src/corelib/plugin/qfactoryloader_p.h b/src/corelib/plugin/qfactoryloader_p.h
index fe722999ae..7815ea0b5d 100644
--- a/src/corelib/plugin/qfactoryloader_p.h
+++ b/src/corelib/plugin/qfactoryloader_p.h
@@ -56,6 +56,7 @@
#include "QtCore/qobject.h"
#include "QtCore/qstringlist.h"
+#include "QtCore/qcborvalue.h"
#include "QtCore/qjsonobject.h"
#include "QtCore/qjsondocument.h"
#include "QtCore/qmap.h"
@@ -66,7 +67,7 @@
QT_BEGIN_NAMESPACE
-QJsonDocument qJsonFromRawLibraryMetaData(const char *raw, qsizetype size);
+QJsonDocument qJsonFromRawLibraryMetaData(const char *raw, qsizetype size, QString *errMsg);
class QFactoryLoaderPrivate;
class Q_CORE_EXPORT QFactoryLoader : public QObject
diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp
index 869ef6181f..aa63ed1a6b 100644
--- a/src/corelib/plugin/qlibrary.cpp
+++ b/src/corelib/plugin/qlibrary.cpp
@@ -268,7 +268,7 @@ static bool findPatternUnloaded(const QString &library, QLibraryPrivate *lib)
*/
bool hasMetaData = false;
qsizetype pos = 0;
- char pattern[] = "qTMETADATA ";
+ char pattern[] = "qTMETADATA ";
pattern[0] = 'Q'; // Ensure the pattern "QTMETADATA" is not found in this library should QPluginLoader ever encounter it.
const ulong plen = qstrlen(pattern);
#if defined (Q_OF_ELF) && defined(Q_CC_GNU)
@@ -314,10 +314,14 @@ static bool findPatternUnloaded(const QString &library, QLibraryPrivate *lib)
bool ret = false;
- if (pos >= 0) {
- if (hasMetaData) {
- const char *data = filedata + pos;
- QJsonDocument doc = qJsonFromRawLibraryMetaData(data, qsizetype(fdlen));
+ if (pos >= 0 && hasMetaData) {
+ const char *data = filedata + pos;
+ QString errMsg;
+ QJsonDocument doc = qJsonFromRawLibraryMetaData(data, fdlen, &errMsg);
+ if (doc.isNull()) {
+ qWarning("Found invalid metadata in lib %s: %s",
+ qPrintable(library), qPrintable(errMsg));
+ } else {
lib->metaData = doc.object();
if (qt_debug_component())
qWarning("Found metadata in lib %s, metadata=\n%s\n",
@@ -679,20 +683,26 @@ bool QLibrary::isLibrary(const QString &fileName)
#endif
}
-typedef const char * (*QtPluginQueryVerificationDataFunction)();
-
-static bool qt_get_metadata(QtPluginQueryVerificationDataFunction pfn, QLibraryPrivate *priv)
+static bool qt_get_metadata(QLibraryPrivate *priv, QString *errMsg)
{
- const char *szData = 0;
- if (!pfn)
- return false;
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ auto getMetaData = [](QFunctionPointer fptr) {
+ auto f = reinterpret_cast<const char * (*)()>(fptr);
+ return qMakePair<const char *, size_t>(f(), INT_MAX);
+ };
+#else
+ auto getMetaData = [](QFunctionPointer fptr) {
+ auto f = reinterpret_cast<QPair<const char *, size_t> (*)()>(fptr);
+ return f();
+ };
+#endif
- szData = pfn();
- if (!szData)
+ QFunctionPointer pfn = priv->resolve("qt_plugin_query_metadata");
+ if (!pfn)
return false;
- // the data is already loaded, so the size doesn't matter
- QJsonDocument doc = qJsonFromRawLibraryMetaData(szData, INT_MAX);
+ auto metaData = getMetaData(pfn);
+ QJsonDocument doc = qJsonFromRawLibraryMetaData(metaData.first, metaData.second, errMsg);
if (doc.isNull())
return false;
priv->metaData = doc.object();
@@ -735,9 +745,7 @@ void QLibraryPrivate::updatePluginState()
} else {
// library is already loaded (probably via QLibrary)
// simply get the target function and call it.
- QtPluginQueryVerificationDataFunction getMetaData = NULL;
- getMetaData = (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_metadata");
- success = qt_get_metadata(getMetaData, this);
+ success = qt_get_metadata(this, &errorString);
}
if (!success) {
diff --git a/src/corelib/plugin/qlibrary_win.cpp b/src/corelib/plugin/qlibrary_win.cpp
index 9368e53b3f..05a93d467e 100644
--- a/src/corelib/plugin/qlibrary_win.cpp
+++ b/src/corelib/plugin/qlibrary_win.cpp
@@ -97,10 +97,10 @@ bool QLibraryPrivate::load_sys()
for (const QString &attempt : qAsConst(attempts)) {
#ifndef Q_OS_WINRT
- pHnd = LoadLibrary((wchar_t*)QDir::toNativeSeparators(attempt).utf16());
+ pHnd = LoadLibrary(reinterpret_cast<const wchar_t*>(QDir::toNativeSeparators(attempt).utf16()));
#else // Q_OS_WINRT
QString path = QDir::toNativeSeparators(QDir::current().relativeFilePath(attempt));
- pHnd = LoadPackagedLibrary((LPCWSTR)path.utf16(), 0);
+ pHnd = LoadPackagedLibrary(reinterpret_cast<LPCWSTR>(path.utf16()), 0);
if (pHnd)
qualifiedFileName = attempt;
#endif // !Q_OS_WINRT
diff --git a/src/corelib/plugin/qplugin.h b/src/corelib/plugin/qplugin.h
index c8200afeeb..676b5047d6 100644
--- a/src/corelib/plugin/qplugin.h
+++ b/src/corelib/plugin/qplugin.h
@@ -56,6 +56,21 @@ QT_BEGIN_NAMESPACE
# endif
#endif
+inline constexpr unsigned char qPluginArchRequirements()
+{
+ return 0
+#ifndef QT_NO_DEBUG
+ | 1
+#endif
+#ifdef __AVX2__
+ | 2
+# ifdef __AVX512F__
+ | 4
+# endif
+#endif
+ ;
+}
+
typedef QObject *(*QtPluginInstanceFunction)();
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
typedef const char *(*QtPluginMetaDataFunction)();
diff --git a/src/corelib/plugin/qplugin_p.h b/src/corelib/plugin/qplugin_p.h
new file mode 100644
index 0000000000..717129268b
--- /dev/null
+++ b/src/corelib/plugin/qplugin_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Intel Corporation.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPLUGIN_P_H
+#define QPLUGIN_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+enum class QtPluginMetaDataKeys {
+ QtVersion,
+ Requirements,
+ IID,
+ ClassName,
+ MetaData
+};
+
+// F(IntKey, StringKey, Description)
+// Keep this list sorted in the order moc should output.
+#define QT_PLUGIN_FOREACH_METADATA(F) \
+ F(QtPluginMetaDataKeys::IID, "IID", "Plugin's Interface ID") \
+ F(QtPluginMetaDataKeys::ClassName, "className", "Plugin class name") \
+ F(QtPluginMetaDataKeys::MetaData, "MetaData", "Other meta data")
+
+QT_END_NAMESPACE
+
+#endif // QPLUGIN_P_H
diff --git a/src/corelib/plugin/qpluginloader.cpp b/src/corelib/plugin/qpluginloader.cpp
index 83cbcd2b44..0f94bb6adf 100644
--- a/src/corelib/plugin/qpluginloader.cpp
+++ b/src/corelib/plugin/qpluginloader.cpp
@@ -475,10 +475,19 @@ QVector<QStaticPlugin> QPluginLoader::staticPlugins()
*/
QJsonObject QStaticPlugin::metaData() const
{
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
// the data is already loaded, so this doesn't matter
qsizetype rawMetaDataSize = INT_MAX;
+ const char *ptr = rawMetaData();
+#else
+ auto ptr = static_cast<const char *>(rawMetaData);
+#endif
- return qJsonFromRawLibraryMetaData(rawMetaData(), rawMetaDataSize).object();
+ QString errMsg;
+ QJsonDocument doc = qJsonFromRawLibraryMetaData(ptr, rawMetaDataSize, &errMsg);
+ Q_ASSERT(doc.isObject());
+ Q_ASSERT(errMsg.isEmpty());
+ return doc.object();
}
QT_END_NAMESPACE
diff --git a/src/corelib/plugin/qsystemlibrary.cpp b/src/corelib/plugin/qsystemlibrary.cpp
index 7c80fbbd42..1f8cef790c 100644
--- a/src/corelib/plugin/qsystemlibrary.cpp
+++ b/src/corelib/plugin/qsystemlibrary.cpp
@@ -121,7 +121,7 @@ HINSTANCE QSystemLibrary::load(const wchar_t *libraryName, bool onlySystemDirect
fullPathAttempt.append(QLatin1Char('\\'));
}
fullPathAttempt.append(fileName);
- HINSTANCE inst = ::LoadLibrary((const wchar_t *)fullPathAttempt.utf16());
+ HINSTANCE inst = ::LoadLibrary(reinterpret_cast<const wchar_t *>(fullPathAttempt.utf16()));
if (inst != 0)
return inst;
}
diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp
index 57ae671897..5714f5236c 100644
--- a/src/corelib/thread/qthread_win.cpp
+++ b/src/corelib/thread/qthread_win.cpp
@@ -318,7 +318,8 @@ void qt_set_thread_name(HANDLE threadId, LPCSTR threadName)
__try
{
- RaiseException(0x406D1388, 0, sizeof(info)/sizeof(DWORD), (const ULONG_PTR*)&info);
+ RaiseException(0x406D1388, 0, sizeof(info)/sizeof(DWORD),
+ reinterpret_cast<const ULONG_PTR*>(&info));
}
__except (EXCEPTION_CONTINUE_EXECUTION)
{
@@ -365,7 +366,7 @@ unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(voi
#if !defined(QT_NO_DEBUG) && defined(Q_CC_MSVC) && !defined(Q_OS_WINRT)
// sets the name of the current thread.
QByteArray objectName = thr->objectName().toLocal8Bit();
- qt_set_thread_name((HANDLE)-1,
+ qt_set_thread_name(HANDLE(-1),
objectName.isEmpty() ?
thr->metaObject()->className() : objectName.constData());
#endif
@@ -508,8 +509,9 @@ void QThread::start(Priority priority)
this, CREATE_SUSPENDED, &(d->id));
#else
// MSVC -MD or -MDd or MinGW build
- d->handle = (Qt::HANDLE) CreateThread(NULL, d->stackSize, (LPTHREAD_START_ROUTINE)QThreadPrivate::start,
- this, CREATE_SUSPENDED, reinterpret_cast<LPDWORD>(&d->id));
+ d->handle = CreateThread(nullptr, d->stackSize,
+ reinterpret_cast<LPTHREAD_START_ROUTINE>(QThreadPrivate::start),
+ this, CREATE_SUSPENDED, reinterpret_cast<LPDWORD>(&d->id));
#endif // Q_OS_WINRT
if (!d->handle) {
diff --git a/src/corelib/tools/qlocale_win.cpp b/src/corelib/tools/qlocale_win.cpp
index 30aefb71c1..e1a61fa9d7 100644
--- a/src/corelib/tools/qlocale_win.cpp
+++ b/src/corelib/tools/qlocale_win.cpp
@@ -274,7 +274,7 @@ QSystemLocalePrivate::SubstitutionType QSystemLocalePrivate::substitution()
QString &QSystemLocalePrivate::substituteDigits(QString &string)
{
ushort zero = zeroDigit().unicode();
- ushort *qch = (ushort *)string.data();
+ ushort *qch = reinterpret_cast<ushort *>(string.data());
for (ushort *end = qch + string.size(); qch != end; ++qch) {
if (*qch >= '0' && *qch <= '9')
*qch = zero + (*qch - '0');
diff --git a/src/corelib/tools/qsimd.cpp b/src/corelib/tools/qsimd.cpp
index 85efd3cded..07a8b022bc 100644
--- a/src/corelib/tools/qsimd.cpp
+++ b/src/corelib/tools/qsimd.cpp
@@ -190,7 +190,9 @@ static inline quint64 detectProcessorFeatures()
static int maxBasicCpuidSupported()
{
-#if defined(Q_CC_GNU)
+#if defined(Q_CC_EMSCRIPTEN)
+ return 6; // All features supported by Emscripten
+#elif defined(Q_CC_GNU)
qregisterint tmp1;
# if Q_PROCESSOR_X86 < 5
@@ -235,7 +237,7 @@ static int maxBasicCpuidSupported()
static void cpuidFeatures01(uint &ecx, uint &edx)
{
-#if defined(Q_CC_GNU)
+#if defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)
qregisterint tmp1;
asm ("xchg " PICreg", %2\n"
"cpuid\n"
@@ -252,6 +254,9 @@ static void cpuidFeatures01(uint &ecx, uint &edx)
__CPUID(1, info);
ecx = info[2];
edx = info[3];
+#else
+ Q_UNUSED(ecx);
+ Q_UNUSED(edx);
#endif
}
@@ -261,7 +266,7 @@ inline void __cpuidex(int info[4], int, __int64) { memset(info, 0, 4*sizeof(int)
static void cpuidFeatures07_00(uint &ebx, uint &ecx, uint &edx)
{
-#if defined(Q_CC_GNU)
+#if defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)
qregisteruint rbx; // in case it's 64-bit
qregisteruint rcx = 0;
qregisteruint rdx = 0;
@@ -294,7 +299,7 @@ inline quint64 _xgetbv(__int64) { return 0; }
#endif
static void xgetbv(uint in, uint &eax, uint &edx)
{
-#if defined(Q_CC_GNU) || defined(Q_CC_GHS)
+#if (defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)) || defined(Q_CC_GHS)
asm (".byte 0x0F, 0x01, 0xD0" // xgetbv instruction
: "=a" (eax), "=d" (edx)
: "c" (in));
@@ -302,6 +307,10 @@ static void xgetbv(uint in, uint &eax, uint &edx)
quint64 result = _xgetbv(in);
eax = result;
edx = result >> 32;
+#else
+ Q_UNUSED(in);
+ Q_UNUSED(eax);
+ Q_UNUSED(edx);
#endif
}
diff --git a/src/corelib/tools/qtimezoneprivate_win.cpp b/src/corelib/tools/qtimezoneprivate_win.cpp
index ec91b7e8a8..ca7ea24fc5 100644
--- a/src/corelib/tools/qtimezoneprivate_win.cpp
+++ b/src/corelib/tools/qtimezoneprivate_win.cpp
@@ -140,15 +140,15 @@ bool equalTzi(const TIME_ZONE_INFORMATION &tzi1, const TIME_ZONE_INFORMATION &tz
#ifdef QT_USE_REGISTRY_TIMEZONE
bool openRegistryKey(const QString &keyPath, HKEY *key)
{
- return (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (const wchar_t*)keyPath.utf16(), 0, KEY_READ, key)
- == ERROR_SUCCESS);
+ return RegOpenKeyEx(HKEY_LOCAL_MACHINE, reinterpret_cast<const wchar_t*>(keyPath.utf16()),
+ 0, KEY_READ, key) == ERROR_SUCCESS;
}
QString readRegistryString(const HKEY &key, const wchar_t *value)
{
wchar_t buffer[MAX_PATH] = {0};
DWORD size = sizeof(wchar_t) * MAX_PATH;
- RegQueryValueEx(key, (LPCWSTR)value, NULL, NULL, (LPBYTE)buffer, &size);
+ RegQueryValueEx(key, value, nullptr, nullptr, reinterpret_cast<LPBYTE>(buffer), &size);
return QString::fromWCharArray(buffer);
}
@@ -156,7 +156,7 @@ int readRegistryValue(const HKEY &key, const wchar_t *value)
{
DWORD buffer;
DWORD size = sizeof(buffer);
- RegQueryValueEx(key, (LPCWSTR)value, NULL, NULL, (LPBYTE)&buffer, &size);
+ RegQueryValueEx(key, value, nullptr, nullptr, reinterpret_cast<LPBYTE>(&buffer), &size);
return buffer;
}
@@ -167,7 +167,7 @@ QWinTimeZonePrivate::QWinTransitionRule readRegistryRule(const HKEY &key,
QWinTimeZonePrivate::QWinTransitionRule rule;
REG_TZI_FORMAT tzi;
DWORD tziSize = sizeof(tzi);
- if (RegQueryValueEx(key, (LPCWSTR)value, NULL, NULL, (BYTE *)&tzi, &tziSize)
+ if (RegQueryValueEx(key, value, nullptr, nullptr, reinterpret_cast<BYTE *>(&tzi), &tziSize)
== ERROR_SUCCESS) {
rule.startYear = 0;
rule.standardTimeBias = tzi.Bias + tzi.StandardBias;
@@ -192,12 +192,12 @@ TIME_ZONE_INFORMATION getRegistryTzi(const QByteArray &windowsId, bool *ok)
if (openRegistryKey(tziKeyPath, &key)) {
DWORD size = sizeof(tzi.DaylightName);
- RegQueryValueEx(key, L"Dlt", NULL, NULL, (LPBYTE)tzi.DaylightName, &size);
+ RegQueryValueEx(key, L"Dlt", nullptr, nullptr, reinterpret_cast<LPBYTE>(tzi.DaylightName), &size);
size = sizeof(tzi.StandardName);
- RegQueryValueEx(key, L"Std", NULL, NULL, (LPBYTE)tzi.StandardName, &size);
+ RegQueryValueEx(key, L"Std", nullptr, nullptr, reinterpret_cast<LPBYTE>(tzi.StandardName), &size);
- if (RegQueryValueEx(key, L"TZI", NULL, NULL, (BYTE *) &regTzi, &regTziSize)
+ if (RegQueryValueEx(key, L"TZI", nullptr, nullptr, reinterpret_cast<BYTE *>(&regTzi), &regTziSize)
== ERROR_SUCCESS) {
tzi.Bias = regTzi.Bias;
tzi.StandardBias = regTzi.StandardBias;
@@ -590,7 +590,7 @@ void QWinTimeZonePrivate::init(const QByteArray &ianaId)
for (int year = startYear; year <= endYear; ++year) {
bool ruleOk;
QWinTransitionRule rule = readRegistryRule(dynamicKey,
- (LPCWSTR)QString::number(year).utf16(),
+ reinterpret_cast<LPCWSTR>(QString::number(year).utf16()),
&ruleOk);
if (ruleOk
// Don't repeat a recurrent rule:
diff --git a/src/corelib/tools/qunicodetables_p.h b/src/corelib/tools/qunicodetables_p.h
index f3fb6ec1b0..3f2e91a9b2 100644
--- a/src/corelib/tools/qunicodetables_p.h
+++ b/src/corelib/tools/qunicodetables_p.h
@@ -72,6 +72,9 @@ struct Properties {
signed short mirrorDiff : 16;
ushort lowerCaseSpecial : 1;
signed short lowerCaseDiff : 15;
+#ifdef Q_OS_WASM
+ unsigned char : 0; //wasm 64 packing trick
+#endif
ushort upperCaseSpecial : 1;
signed short upperCaseDiff : 15;
ushort titleCaseSpecial : 1;
@@ -80,6 +83,9 @@ struct Properties {
signed short caseFoldDiff : 15;
ushort unicodeVersion : 8; /* 5 used */
ushort nfQuickCheck : 8;
+#ifdef Q_OS_WASM
+ unsigned char : 0; //wasm 64 packing trick
+#endif
ushort graphemeBreakClass : 5; /* 5 used */
ushort wordBreakClass : 5; /* 5 used */
ushort sentenceBreakClass : 8; /* 4 used */
diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri
index 6b180602c2..995bab694e 100644
--- a/src/corelib/tools/tools.pri
+++ b/src/corelib/tools/tools.pri
@@ -221,7 +221,7 @@ qtConfig(system-doubleconversion) {
}
# Note: libm should be present by default becaue this is C++
-unix:!macx-icc:!vxworks:!haiku:!integrity: LIBS_PRIVATE += -lm
+unix:!macx-icc:!vxworks:!haiku:!integrity:!wasm: LIBS_PRIVATE += -lm
TR_EXCLUDE += ../3rdparty/*
diff --git a/src/gui/configure.json b/src/gui/configure.json
index 26a5ae9a3d..4741ed345a 100644
--- a/src/gui/configure.json
+++ b/src/gui/configure.json
@@ -164,7 +164,8 @@
},
"sources": [
{ "type": "pkgConfig", "args": "freetype2" },
- { "type": "freetype", "libs": "-lfreetype" }
+ { "type": "freetype", "libs": "-lfreetype", "condition": "!config.wasm" },
+ { "type": "freetype", "libs": "-s USE_FREETYPE=1", "condition": "config.wasm" }
]
},
"fontconfig": {
@@ -308,7 +309,8 @@
{ "libs": "-llibpng16", "condition": "config.msvc" },
{ "libs": "-llibpng", "condition": "config.msvc" },
{ "libs": "-lpng16", "condition": "!config.msvc" },
- { "libs": "-lpng", "condition": "!config.msvc" }
+ { "libs": "-lpng", "condition": "!config.msvc" },
+ { "libs": "-s USE_LIBPNG=1", "condition": "config.wasm" }
],
"use": [
{ "lib": "zlib", "condition": "features.system-zlib" }
@@ -1111,7 +1113,7 @@
},
"opengles3": {
"label": "OpenGL ES 3.0",
- "condition": "features.opengles2 && !features.angle && tests.opengles3",
+ "condition": "features.opengles2 && !features.angle && tests.opengles3 && !config.wasm",
"output": [
"publicFeature",
{ "type": "define", "name": "QT_OPENGL_ES_3" }
@@ -1138,7 +1140,7 @@
"enable": "input.opengl == 'desktop'",
"disable": "input.opengl == 'es2' || input.opengl == 'dynamic' || input.opengl == 'no'",
"condition": "(config.win32 && !config.winrt && !features.opengles2 && (config.msvc || libs.opengl))
- || (!config.watchos && !config.win32 && libs.opengl)"
+ || (!config.watchos && !config.win32 && !config.wasm && libs.opengl)"
},
"opengl-dynamic": {
"label": "Dynamic OpenGL",
diff --git a/src/gui/configure.pri b/src/gui/configure.pri
index b40536e41d..2971fd136e 100644
--- a/src/gui/configure.pri
+++ b/src/gui/configure.pri
@@ -55,6 +55,7 @@ defineTest(qtConfTest_qpaDefaultPlatform) {
else: qnx: name = qnx
else: integrity: name = integrityfb
else: haiku: name = haiku
+ else: wasm: name = webassembly
else: name = xcb
$${1}.value = $$name
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index 93e8b6ee8f..bc1f83a9c8 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -114,6 +114,10 @@
# include <QtCore/QLibraryInfo>
#endif // Q_OS_WIN
+#ifdef Q_OS_WASM
+#include <emscripten.h>
+#endif
+
#include <qtgui_tracepoints_p.h>
#include <ctype.h>
@@ -1620,7 +1624,13 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate()
qt_gl_set_global_share_context(0);
}
#endif
-
+#ifdef Q_OS_WASM
+ EM_ASM(
+ // unmount persistent directory as IDBFS
+ // see QTBUG-70002
+ FS.unmount('/home/web_user');
+ );
+#endif
platform_integration->destroy();
delete platform_theme;
diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp
index 7bf941b9a1..cd50294a6c 100644
--- a/src/gui/kernel/qopenglcontext.cpp
+++ b/src/gui/kernel/qopenglcontext.cpp
@@ -977,8 +977,11 @@ bool QOpenGLContext::makeCurrent(QSurface *surface)
if (!surface->surfaceHandle())
return false;
if (!surface->supportsOpenGL()) {
+#ifndef Q_OS_WASM // ### work around the WASM platform plugin using QOpenGLContext with raster surfaces.
+ // see QTBUG-70076
qWarning() << "QOpenGLContext::makeCurrent() called with non-opengl surface" << surface;
return false;
+#endif
}
QOpenGLContext *previous = QOpenGLContextPrivate::setCurrentContext(this);
diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h
index c3fb19d21a..492f559f22 100644
--- a/src/gui/kernel/qwindowsysteminterface_p.h
+++ b/src/gui/kernel/qwindowsysteminterface_p.h
@@ -365,7 +365,7 @@ public:
QUrl url;
};
- class TabletEvent : public InputEvent {
+ class Q_GUI_EXPORT TabletEvent : public InputEvent {
public:
static void handleTabletEvent(QWindow *w, const QPointF &local, const QPointF &global,
int device, int pointerType, Qt::MouseButtons buttons, qreal pressure, int xTilt, int yTilt,
diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp
index 6486a447ee..cae3d516c4 100644
--- a/src/gui/opengl/qopenglframebufferobject.cpp
+++ b/src/gui/opengl/qopenglframebufferobject.cpp
@@ -142,6 +142,14 @@ QT_BEGIN_NAMESPACE
#define GL_CONTEXT_LOST 0x0507
#endif
+#ifndef GL_DEPTH_STENCIL_ATTACHMENT
+#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
+#endif
+
+#ifndef GL_DEPTH_STENCIL
+#define GL_DEPTH_STENCIL 0x84F9
+#endif
+
/*!
@@ -619,7 +627,11 @@ void QOpenGLFramebufferObjectPrivate::initDepthStencilAttachments(QOpenGLContext
// free existing attachments
if (depth_buffer_guard) {
+#ifdef Q_OS_WASM
+ funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
+#else
funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
+#endif
depth_buffer_guard->free();
}
if (stencil_buffer_guard) {
@@ -637,7 +649,35 @@ void QOpenGLFramebufferObjectPrivate::initDepthStencilAttachments(QOpenGLContext
// In practice, a combined depth-stencil buffer is supported by all desktop platforms, while a
// separate stencil buffer is not. On embedded devices however, a combined depth-stencil buffer
// might not be supported while separate buffers are, according to QTBUG-12861.
+#ifdef Q_OS_WASM
+ // WebGL doesn't allow separately attach buffers to
+ // STENCIL_ATTACHMENT and DEPTH_ATTACHMENT
+ // QTBUG-69913
+ if (attachment == QOpenGLFramebufferObject::CombinedDepthStencil) {
+ funcs.glGenRenderbuffers(1, &depth_buffer);
+ funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
+ Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer));
+
+ GLenum storageFormat = GL_DEPTH_STENCIL;
+
+ if (samples != 0 ) {
+ funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
+ storageFormat, dsSize.width(), dsSize.height());
+ } else {
+ funcs.glRenderbufferStorage(GL_RENDERBUFFER, storageFormat,
+ dsSize.width(), dsSize.height());
+ }
+
+ funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
+ GL_RENDERBUFFER, depth_buffer);
+ valid = checkFramebufferStatus(ctx);
+ if (!valid) {
+ funcs.glDeleteRenderbuffers(1, &depth_buffer);
+ depth_buffer = 0;
+ }
+ }
+#else
if (attachment == QOpenGLFramebufferObject::CombinedDepthStencil
&& funcs.hasOpenGLExtension(QOpenGLExtensions::PackedDepthStencil))
{
@@ -729,11 +769,16 @@ void QOpenGLFramebufferObjectPrivate::initDepthStencilAttachments(QOpenGLContext
stencil_buffer = 0;
}
}
+#endif //Q_OS_WASM
// The FBO might have become valid after removing the depth or stencil buffer.
valid = checkFramebufferStatus(ctx);
+#ifdef Q_OS_WASM
+ if (depth_buffer) {
+#else
if (depth_buffer && stencil_buffer) {
+#endif
fbo_attachment = QOpenGLFramebufferObject::CombinedDepthStencil;
} else if (depth_buffer) {
fbo_attachment = QOpenGLFramebufferObject::Depth;
diff --git a/src/gui/painting/qimagescale.cpp b/src/gui/painting/qimagescale.cpp
index ca7930500e..96da5e029c 100644
--- a/src/gui/painting/qimagescale.cpp
+++ b/src/gui/painting/qimagescale.cpp
@@ -564,7 +564,10 @@ static void qt_qimageScaleRgba64_up_xy(QImageScaleInfo *isi, QRgba64 *dest,
for (int x = 0; x < dw; x++) {
const QRgba64 *pix = sptr + xpoints[x];
const int xap = xapoints[x];
- *dptr = interpolate256(pix[0], 256 - xap, pix[1], xap);
+ if (xap > 0)
+ *dptr = interpolate256(pix[0], 256 - xap, pix[1], xap);
+ else
+ *dptr = pix[0];
dptr++;
}
}
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index 3b64ee0136..64623c86df 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -1327,7 +1327,7 @@ const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSy
resolveTable:
*isSymbolFont = (symbolTable > -1);
- quint32 unicode_table;
+ quint32 unicode_table = 0;
if (!qSafeFromBigEndian(maps + 8 * tableToUse + 4, endPtr, &unicode_table))
return 0;
diff --git a/src/network/access/access.pri b/src/network/access/access.pri
index a129beda15..b068f96283 100644
--- a/src/network/access/access.pri
+++ b/src/network/access/access.pri
@@ -68,6 +68,13 @@ qtConfig(networkdiskcache) {
mac: LIBS_PRIVATE += -framework Security
+wasm {
+ SOURCES += \
+ access/qnetworkreplywasmimpl.cpp
+ HEADERS += \
+ access/qnetworkreplywasmimpl_p.h
+}
+
include($$PWD/../../3rdparty/zlib_dependency.pri)
qtConfig(http) {
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index 96e3f92db1..bec98a3f58 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -82,6 +82,9 @@
#include <SystemConfiguration/SystemConfiguration.h>
#include <Security/SecKeychain.h>
#endif
+#ifdef Q_OS_WASM
+#include "qnetworkreplywasmimpl_p.h"
+#endif
QT_BEGIN_NAMESPACE
@@ -1344,6 +1347,16 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
bool isLocalFile = req.url().isLocalFile();
QString scheme = req.url().scheme();
+#ifdef Q_OS_WASM
+ if (scheme == QLatin1String("http") || scheme == QLatin1String("https")) {
+ QNetworkReplyWasmImpl *reply = new QNetworkReplyWasmImpl(this);
+ QNetworkReplyWasmImplPrivate *priv = reply->d_func();
+ priv->manager = this;
+ priv->setup(op, req, outgoingData);
+ return reply;
+ }
+#endif
+
// fast path for GET on file:// URLs
// The QNetworkAccessFileBackend will right now only be used for PUT
if (op == QNetworkAccessManager::GetOperation
diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h
index a0ce3eddcd..67b3a8b71b 100644
--- a/src/network/access/qnetworkaccessmanager.h
+++ b/src/network/access/qnetworkaccessmanager.h
@@ -195,6 +195,9 @@ private:
friend class QNetworkReplyHttpImplPrivate;
friend class QNetworkReplyFileImpl;
+#ifdef Q_OS_WASM
+ friend class QNetworkReplyWasmImpl;
+#endif
Q_DECLARE_PRIVATE(QNetworkAccessManager)
Q_PRIVATE_SLOT(d_func(), void _q_replyFinished())
Q_PRIVATE_SLOT(d_func(), void _q_replyEncrypted())
diff --git a/src/network/access/qnetworkreplywasmimpl.cpp b/src/network/access/qnetworkreplywasmimpl.cpp
new file mode 100644
index 0000000000..9c2ff8fb89
--- /dev/null
+++ b/src/network/access/qnetworkreplywasmimpl.cpp
@@ -0,0 +1,640 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qnetworkreplywasmimpl_p.h"
+#include "qnetworkrequest.h"
+
+#include <QtCore/qtimer.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qthread.h>
+
+#include <private/qnetworkaccessmanager_p.h>
+#include <private/qnetworkfile_p.h>
+
+#include <iostream>
+
+QT_BEGIN_NAMESPACE
+
+QNetworkReplyWasmImplPrivate::QNetworkReplyWasmImplPrivate()
+ : QNetworkReplyPrivate()
+ , managerPrivate(0)
+ , downloadBufferReadPosition(0)
+ , downloadBufferCurrentSize(0)
+ , totalDownloadSize(0)
+ , percentFinished(0)
+{
+}
+
+QNetworkReplyWasmImplPrivate::~QNetworkReplyWasmImplPrivate()
+{
+}
+
+QNetworkReplyWasmImpl::~QNetworkReplyWasmImpl()
+{
+}
+
+QNetworkReplyWasmImpl::QNetworkReplyWasmImpl(QObject *parent)
+ : QNetworkReply(*new QNetworkReplyWasmImplPrivate(), parent)
+{
+}
+
+QByteArray QNetworkReplyWasmImpl::methodName() const
+{
+ switch (operation()) {
+ case QNetworkAccessManager::HeadOperation:
+ return "HEAD";
+ case QNetworkAccessManager::GetOperation:
+ return "GET";
+ case QNetworkAccessManager::PutOperation:
+ return "PUT";
+ case QNetworkAccessManager::PostOperation:
+ return "POST";
+ case QNetworkAccessManager::DeleteOperation:
+ return "DELETE";
+ default:
+ break;
+ }
+ return QByteArray();
+}
+
+void QNetworkReplyWasmImpl::close()
+{
+ QNetworkReply::close();
+}
+
+void QNetworkReplyWasmImpl::abort()
+{
+ close();
+}
+
+qint64 QNetworkReplyWasmImpl::bytesAvailable() const
+{
+ Q_D(const QNetworkReplyWasmImpl);
+
+ if (!d->isFinished)
+ return QNetworkReply::bytesAvailable();
+
+ return QNetworkReply::bytesAvailable() + d->downloadBufferCurrentSize - d->downloadBufferReadPosition;
+}
+
+bool QNetworkReplyWasmImpl::isSequential() const
+{
+ return true;
+}
+
+qint64 QNetworkReplyWasmImpl::size() const
+{
+ return QNetworkReply::size();
+}
+
+/*!
+ \internal
+*/
+qint64 QNetworkReplyWasmImpl::readData(char *data, qint64 maxlen)
+{
+ Q_D(QNetworkReplyWasmImpl);
+
+ qint64 howMuch = qMin(maxlen, (d->downloadBuffer.size() - d->downloadBufferReadPosition));
+ memcpy(data, d->downloadBuffer.constData(), howMuch);
+ d->downloadBufferReadPosition += howMuch;
+
+ return howMuch;
+}
+
+void QNetworkReplyWasmImplPrivate::setup(QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *data)
+{
+ Q_Q(QNetworkReplyWasmImpl);
+
+ outgoingData = data;
+ request = req;
+ url = request.url();
+ operation = op;
+
+ q->QIODevice::open(QIODevice::ReadOnly);
+ if (outgoingData && outgoingData->isSequential()) {
+ bool bufferingDisallowed =
+ request.attribute(QNetworkRequest::DoNotBufferUploadDataAttribute, false).toBool();
+
+ if (bufferingDisallowed) {
+ // if a valid content-length header for the request was supplied, we can disable buffering
+ // if not, we will buffer anyway
+ if (!request.header(QNetworkRequest::ContentLengthHeader).isValid()) {
+ state = Buffering;
+ _q_bufferOutgoingData();
+ return;
+ }
+ } else {
+ // doSendRequest will be called when the buffering has finished.
+ state = Buffering;
+ _q_bufferOutgoingData();
+ return;
+ }
+ }
+ // No outgoing data (POST, ..)
+ doSendRequest();
+}
+
+void QNetworkReplyWasmImplPrivate::onLoadCallback(void *data, int statusCode, int statusReason, int readyState, int buffer, int bufferSize)
+{
+ QNetworkReplyWasmImplPrivate *handler = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(data);
+
+ const QString reasonStr = QString::fromUtf8(reinterpret_cast<char *>(statusReason));
+
+ switch (readyState) {
+ case 0://unsent
+ break;
+ case 1://opened
+ break;
+ case 2://headers received
+ break;
+ case 3://loading
+ break;
+ case 4: {//done
+ handler->q_func()->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, statusCode);
+ if (!reasonStr.isEmpty())
+ handler->q_func()->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, reasonStr);
+
+ if (statusCode >= 400) {
+ if (!reasonStr.isEmpty())
+ handler->emitReplyError(handler->statusCodeFromHttp(statusCode, handler->request.url()), reasonStr);
+ } else {
+ handler->dataReceived(reinterpret_cast<char *>(buffer), bufferSize);
+ }
+ }
+ break;
+ };
+ }
+
+void QNetworkReplyWasmImplPrivate::onProgressCallback(void* data, int bytesWritten, int total, uint timestamp)
+{
+ Q_UNUSED(timestamp);
+
+ QNetworkReplyWasmImplPrivate *handler = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(data);
+ handler->emitDataReadProgress(bytesWritten, total);
+}
+
+void QNetworkReplyWasmImplPrivate::onRequestErrorCallback(void* data, int statusCode, int statusReason)
+{
+ QString reasonStr = QString::fromUtf8(reinterpret_cast<char *>(statusReason));
+
+ QNetworkReplyWasmImplPrivate *handler = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(data);
+
+ handler->q_func()->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, statusCode);
+ if (!reasonStr.isEmpty())
+ handler->q_func()->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, reasonStr);
+
+ if (statusCode >= 400) {
+ if (!reasonStr.isEmpty())
+ handler->emitReplyError(handler->statusCodeFromHttp(statusCode, handler->request.url()), reasonStr);
+ }
+}
+
+void QNetworkReplyWasmImplPrivate::onResponseHeadersCallback(void* data, int headers)
+{
+ QNetworkReplyWasmImplPrivate *handler = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(data);
+ handler->headersReceived(reinterpret_cast<char *>(headers));
+}
+
+void QNetworkReplyWasmImplPrivate::doSendRequest()
+{
+ Q_Q(QNetworkReplyWasmImpl);
+ totalDownloadSize = 0;
+ jsRequest(QString::fromUtf8(q->methodName()), // GET POST
+ request.url().toString(),
+ (void *)&onLoadCallback,
+ (void *)&onProgressCallback,
+ (void *)&onRequestErrorCallback,
+ (void *)&onResponseHeadersCallback);
+}
+
+/* const QString &body, const QList<QPair<QByteArray, QByteArray> > &headers ,*/
+void QNetworkReplyWasmImplPrivate::jsRequest(const QString &verb, const QString &url,
+ void *loadCallback, void *progressCallback,
+ void *errorCallback, void *onResponseHeadersCallback)
+{
+ QString extraDataString;
+
+ QByteArray extraData;
+ if (outgoingData)
+ extraData = outgoingData->readAll();
+
+ if (extraData.size() > 0)
+ extraDataString.fromUtf8(extraData);
+
+ if (extraDataString.size() >= 0 && verb == QStringLiteral("POST") && extraDataString.startsWith(QStringLiteral("?")))
+ extraDataString.remove(QStringLiteral("?"));
+
+ // Probably a good idea to save any shared pointers as members in C++
+ // so the objects they point to survive as long as you need them
+
+ QStringList headersList;
+ for (auto header : request.rawHeaderList())
+ headersList << QString::fromUtf8(header + ":" + request.rawHeader(header));
+
+ EM_ASM_ARGS({
+ var verb = Pointer_stringify($0);
+ var url = Pointer_stringify($1);
+ var onLoadCallbackPointer = $2;
+ var onProgressCallbackPointer = $3;
+ var onErrorCallbackPointer = $4;
+ var onHeadersCallback = $5;
+ var handler = $8;
+
+ var dataToSend;
+ var extraRequestData = Pointer_stringify($6); // request parameters
+ var headersData = Pointer_stringify($7);
+
+ var xhr;
+ xhr = new XMLHttpRequest();
+ xhr.responseType = 'arraybuffer';
+
+ xhr.open(verb, url, true); //async
+
+ function handleError(xhrStatusCode, xhrStatusText) {
+ var errorPtr = allocate(intArrayFromString(xhrStatusText), 'i8', ALLOC_NORMAL);
+ Runtime.dynCall('viii', onErrorCallbackPointer, [handler, xhrStatusCode, errorPtr]);
+ _free(errorPtr);
+ }
+
+ if (headersData) {
+ var headers = headersData.split("&");
+ for (var i = 0; i < headers.length; i++) {
+ var header = headers[i].split(":")[0];
+ var value = headers[i].split(":")[1];
+
+ if (verb === 'POST' && value.toLowerCase().includes('json')) {
+ if (extraRequestData) {
+ xhr.responseType = 'json';
+ dataToSend = extraRequestData;
+ }
+ }
+ if (verb === 'POST' && value.toLowerCase().includes('form')) {
+ if (extraRequestData) {
+ var formData = new FormData();
+ var extra = extraRequestData.split("&");
+ for (var i = 0; i < extra.length; i++) {
+ formData.append(extra[i].split("=")[0],extra[i].split("=")[1]);
+ }
+ dataToSend = formData;
+ }
+ }
+ xhr.setRequestHeader(header, value);
+ }
+ }
+
+ xhr.onprogress = function(e) {
+ switch (xhr.status) {
+ case 200:
+ case 206:
+ case 300:
+ case 301:
+ case 302: {
+ var date = xhr.getResponseHeader('Last-Modified');
+ date = ((date != null) ? new Date(date).getTime() / 1000 : 0);
+ Runtime.dynCall('viiii', onProgressCallbackPointer, [handler, e.loaded, e.total, date]);
+ }
+ break;
+ }
+ };
+
+ xhr.onreadystatechange = function() {
+ if (this.readyState == this.HEADERS_RECEIVED) {
+ var responseStr = this.getAllResponseHeaders();
+ if (responseStr.length > 0) {
+ var ptr = allocate(intArrayFromString(responseStr), 'i8', ALLOC_NORMAL);
+ Runtime.dynCall('vii', onHeadersCallback, [handler, ptr]);
+ _free(ptr);
+ }
+ }
+ };
+
+ xhr.onload = function(e) {
+ if (xhr.status >= 300) { //error
+ handleError(xhr.status, xhr.statusText);
+ } else {
+ if (this.status == 200 || this.status == 203) {
+ var datalength;
+ var byteArray = 0;
+ var buffer;
+ if (this.responseType.length === 0 || this.responseType === 'document') {
+ byteArray = new Uint8Array(this.responseText);
+ } else if (this.responseType === 'json') {
+ var jsonResponse = JSON.stringify(this.response);
+ buffer = allocate(intArrayFromString(jsonResponse), 'i8', ALLOC_NORMAL);
+ datalength = jsonResponse.length;
+ } else if (this.responseType === 'arraybuffer') {
+ byteArray = new Uint8Array(xhr.response);
+ }
+ if (byteArray != 0 ) {
+ datalength = byteArray.length;
+ buffer = _malloc(datalength);
+ HEAPU8.set(byteArray, buffer);
+ }
+ var reasonPtr = allocate(intArrayFromString(this.statusText), 'i8', ALLOC_NORMAL);
+ Runtime.dynCall('viiiiii', onLoadCallbackPointer, [handler, this.status, reasonPtr, this.readyState, buffer, datalength]);
+ _free(buffer);
+ _free(reasonPtr);
+ }
+ }
+ };
+
+ xhr.onerror = function(e) {
+ handleError(xhr.status, xhr.statusText);
+ };
+ //TODO other operations, handle user/pass, handle binary data, data streaming
+ xhr.send(dataToSend);
+
+ }, verb.toLatin1().data(),
+ url.toLatin1().data(),
+ loadCallback,
+ progressCallback,
+ errorCallback,
+ onResponseHeadersCallback,
+ extraDataString.size() > 0 ? extraDataString.toLatin1().data() : extraData.data(),
+ headersList.join(QStringLiteral("&")).toLatin1().data(),
+ this
+ );
+}
+
+void QNetworkReplyWasmImplPrivate::emitReplyError(QNetworkReply::NetworkError errorCode, const QString &errorString)
+{
+ Q_UNUSED(errorCode)
+ Q_Q(QNetworkReplyWasmImpl);
+
+ q->setError(errorCode, errorString);
+ emit q->error(errorCode);
+
+ q->setFinished(true);
+ emit q->finished();
+}
+
+void QNetworkReplyWasmImplPrivate::emitDataReadProgress(qint64 bytesReceived, qint64 bytesTotal)
+{
+ Q_Q(QNetworkReplyWasmImpl);
+
+ totalDownloadSize = bytesTotal;
+
+ percentFinished = (bytesReceived / bytesTotal) * 100;
+
+ emit q->downloadProgress(bytesReceived, totalDownloadSize);
+}
+
+void QNetworkReplyWasmImplPrivate::dataReceived(char *buffer, int bufferSize)
+{
+ Q_Q(QNetworkReplyWasmImpl);
+
+ if (bufferSize > 0)
+ q->setReadBufferSize(bufferSize);
+
+ bytesDownloaded = bufferSize;
+
+ if (percentFinished != 100)
+ downloadBufferCurrentSize += bufferSize;
+ else
+ downloadBufferCurrentSize = bufferSize;
+
+ totalDownloadSize = downloadBufferCurrentSize;
+
+ downloadBuffer.append(buffer, bufferSize);
+
+ if (downloadBufferCurrentSize == totalDownloadSize) {
+ q->setFinished(true);
+ emit q->finished();
+ }
+}
+
+//taken from qnetworkrequest.cpp
+static int parseHeaderName(const QByteArray &headerName)
+{
+ if (headerName.isEmpty())
+ return -1;
+
+ switch (tolower(headerName.at(0))) {
+ case 'c':
+ if (qstricmp(headerName.constData(), "content-type") == 0)
+ return QNetworkRequest::ContentTypeHeader;
+ else if (qstricmp(headerName.constData(), "content-length") == 0)
+ return QNetworkRequest::ContentLengthHeader;
+ else if (qstricmp(headerName.constData(), "cookie") == 0)
+ return QNetworkRequest::CookieHeader;
+ break;
+
+ case 'l':
+ if (qstricmp(headerName.constData(), "location") == 0)
+ return QNetworkRequest::LocationHeader;
+ else if (qstricmp(headerName.constData(), "last-modified") == 0)
+ return QNetworkRequest::LastModifiedHeader;
+ break;
+
+ case 's':
+ if (qstricmp(headerName.constData(), "set-cookie") == 0)
+ return QNetworkRequest::SetCookieHeader;
+ else if (qstricmp(headerName.constData(), "server") == 0)
+ return QNetworkRequest::ServerHeader;
+ break;
+
+ case 'u':
+ if (qstricmp(headerName.constData(), "user-agent") == 0)
+ return QNetworkRequest::UserAgentHeader;
+ break;
+ }
+
+ return -1; // nothing found
+}
+
+
+void QNetworkReplyWasmImplPrivate::headersReceived(char *buffer)
+{
+ Q_Q(QNetworkReplyWasmImpl);
+
+ QString bufferString = QString::fromUtf8(buffer);
+ if (!bufferString.isEmpty()) {
+ QStringList headers = bufferString.split(QString::fromUtf8("\r\n"), QString::SkipEmptyParts);
+
+ for (int i = 0; i < headers.size(); i++) {
+ QString headerName = headers.at(i).split(QString::fromUtf8(": ")).at(0);
+ QString headersValue = headers.at(i).split(QString::fromUtf8(": ")).at(1);
+ if (headerName.isEmpty() || headersValue.isEmpty())
+ continue;
+
+ int headerIndex = parseHeaderName(headerName.toLocal8Bit());
+
+ if (headerIndex == -1)
+ q->setRawHeader(headerName.toLocal8Bit(), headersValue.toLocal8Bit());
+ else
+ q->setHeader(static_cast<QNetworkRequest::KnownHeaders>(headerIndex), (QVariant)headersValue);
+ }
+ }
+ emit q->metaDataChanged();
+}
+
+void QNetworkReplyWasmImplPrivate::_q_bufferOutgoingDataFinished()
+{
+ Q_Q(QNetworkReplyWasmImpl);
+
+ // make sure this is only called once, ever.
+ //_q_bufferOutgoingData may call it or the readChannelFinished emission
+ if (state != Buffering)
+ return;
+
+ // disconnect signals
+ QObject::disconnect(outgoingData, SIGNAL(readyRead()), q, SLOT(_q_bufferOutgoingData()));
+ QObject::disconnect(outgoingData, SIGNAL(readChannelFinished()), q, SLOT(_q_bufferOutgoingDataFinished()));
+
+ // finally, start the request
+ doSendRequest();
+}
+
+void QNetworkReplyWasmImplPrivate::_q_bufferOutgoingData()
+{
+ Q_Q(QNetworkReplyWasmImpl);
+
+ if (!outgoingDataBuffer) {
+ // first call, create our buffer
+ outgoingDataBuffer = QSharedPointer<QRingBuffer>::create();
+
+ QObject::connect(outgoingData, SIGNAL(readyRead()), q, SLOT(_q_bufferOutgoingData()));
+ QObject::connect(outgoingData, SIGNAL(readChannelFinished()), q, SLOT(_q_bufferOutgoingDataFinished()));
+ }
+
+ qint64 bytesBuffered = 0;
+ qint64 bytesToBuffer = 0;
+
+ // read data into our buffer
+ forever {
+ bytesToBuffer = outgoingData->bytesAvailable();
+ // unknown? just try 2 kB, this also ensures we always try to read the EOF
+ if (bytesToBuffer <= 0)
+ bytesToBuffer = 2*1024;
+
+ char *dst = outgoingDataBuffer->reserve(bytesToBuffer);
+ bytesBuffered = outgoingData->read(dst, bytesToBuffer);
+
+ if (bytesBuffered == -1) {
+ // EOF has been reached.
+ outgoingDataBuffer->chop(bytesToBuffer);
+
+ _q_bufferOutgoingDataFinished();
+ break;
+ } else if (bytesBuffered == 0) {
+ // nothing read right now, just wait until we get called again
+ outgoingDataBuffer->chop(bytesToBuffer);
+
+ break;
+ } else {
+ // don't break, try to read() again
+ outgoingDataBuffer->chop(bytesToBuffer - bytesBuffered);
+ }
+ }
+}
+
+//taken from qhttpthreaddelegate.cpp
+QNetworkReply::NetworkError QNetworkReplyWasmImplPrivate::statusCodeFromHttp(int httpStatusCode, const QUrl &url)
+{
+ QNetworkReply::NetworkError code;
+ // we've got an error
+ switch (httpStatusCode) {
+ case 400: // Bad Request
+ code = QNetworkReply::ProtocolInvalidOperationError;
+ break;
+
+ case 401: // Authorization required
+ code = QNetworkReply::AuthenticationRequiredError;
+ break;
+
+ case 403: // Access denied
+ code = QNetworkReply::ContentAccessDenied;
+ break;
+
+ case 404: // Not Found
+ code = QNetworkReply::ContentNotFoundError;
+ break;
+
+ case 405: // Method Not Allowed
+ code = QNetworkReply::ContentOperationNotPermittedError;
+ break;
+
+ case 407:
+ code = QNetworkReply::ProxyAuthenticationRequiredError;
+ break;
+
+ case 409: // Resource Conflict
+ code = QNetworkReply::ContentConflictError;
+ break;
+
+ case 410: // Content no longer available
+ code = QNetworkReply::ContentGoneError;
+ break;
+
+ case 418: // I'm a teapot
+ code = QNetworkReply::ProtocolInvalidOperationError;
+ break;
+
+ case 500: // Internal Server Error
+ code = QNetworkReply::InternalServerError;
+ break;
+
+ case 501: // Server does not support this functionality
+ code = QNetworkReply::OperationNotImplementedError;
+ break;
+
+ case 503: // Service unavailable
+ code = QNetworkReply::ServiceUnavailableError;
+ break;
+
+ default:
+ if (httpStatusCode > 500) {
+ // some kind of server error
+ code = QNetworkReply::UnknownServerError;
+ } else if (httpStatusCode >= 400) {
+ // content error we did not handle above
+ code = QNetworkReply::UnknownContentError;
+ } else {
+ qWarning("QNetworkAccess: got HTTP status code %d which is not expected from url: \"%s\"",
+ httpStatusCode, qPrintable(url.toString()));
+ code = QNetworkReply::ProtocolFailure;
+ }
+ };
+
+ return code;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkreplywasmimpl_p.h b/src/network/access/qnetworkreplywasmimpl_p.h
new file mode 100644
index 0000000000..a707390503
--- /dev/null
+++ b/src/network/access/qnetworkreplywasmimpl_p.h
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QNETWORKREPLYWASMIMPL_H
+#define QNETWORKREPLYWASMIMPL_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Access API. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qnetworkreply.h"
+#include "qnetworkreply_p.h"
+#include "qnetworkaccessmanager.h"
+
+#include <QtCore/qfile.h>
+
+#include <private/qtnetworkglobal_p.h>
+#include <private/qabstractfileengine_p.h>
+
+#include <emscripten.h>
+#include <emscripten/html5.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIODevice;
+
+class QNetworkReplyWasmImplPrivate;
+class QNetworkReplyWasmImpl: public QNetworkReply
+{
+ Q_OBJECT
+public:
+ QNetworkReplyWasmImpl(QObject *parent = nullptr);
+ ~QNetworkReplyWasmImpl();
+ virtual void abort() override;
+
+ // reimplemented from QNetworkReply
+ virtual void close() override;
+ virtual qint64 bytesAvailable() const override;
+ virtual bool isSequential () const override;
+ qint64 size() const override;
+
+ virtual qint64 readData(char *data, qint64 maxlen) override;
+
+ void setup(QNetworkAccessManager::Operation op, const QNetworkRequest &request,
+ QIODevice *outgoingData);
+
+ Q_DECLARE_PRIVATE(QNetworkReplyWasmImpl)
+
+ Q_PRIVATE_SLOT(d_func(), void emitReplyError(QNetworkReply::NetworkError errorCode, const QString &errorString))
+ Q_PRIVATE_SLOT(d_func(), void emitDataReadProgress(qint64 done, qint64 total))
+ Q_PRIVATE_SLOT(d_func(), void dataReceived(char *buffer, int bufferSize))
+
+private:
+ QByteArray methodName() const;
+
+};
+
+class QNetworkReplyWasmImplPrivate: public QNetworkReplyPrivate
+{
+public:
+ QNetworkReplyWasmImplPrivate();
+ ~QNetworkReplyWasmImplPrivate();
+
+ QNetworkAccessManagerPrivate *managerPrivate;
+ void doSendRequest();
+
+ void jsRequest(const QString &verb, const QString &url, void *, void *, void *, void *);
+
+ static void onLoadCallback(void *data, int statusCode, int statusReason, int readyState, int textBuffer, int size);
+ static void onProgressCallback(void *data, int done, int bytesTotal, uint timestamp);
+ static void onRequestErrorCallback(void *data, int statusCode, int statusReason);
+ static void onStateChangedCallback(int status);
+ static void onResponseHeadersCallback(void *data, int headers);
+
+ void emitReplyError(QNetworkReply::NetworkError errorCode, const QString &);
+ void emitDataReadProgress(qint64 done, qint64 total);
+ void dataReceived(char *buffer, int bufferSize);
+ void headersReceived(char *buffer);
+
+ void setup(QNetworkAccessManager::Operation op, const QNetworkRequest &request,
+ QIODevice *outgoingData);
+
+ State state;
+ void _q_bufferOutgoingData();
+ void _q_bufferOutgoingDataFinished();
+
+ QSharedPointer<QAtomicInt> pendingDownloadData;
+ QSharedPointer<QAtomicInt> pendingDownloadProgress;
+
+ qint64 bytesDownloaded;
+ qint64 bytesBuffered;
+
+ qint64 downloadBufferReadPosition;
+ qint64 downloadBufferCurrentSize;
+ qint64 totalDownloadSize;
+ qint64 percentFinished;
+ QByteArray downloadBuffer;
+
+ QIODevice *outgoingData;
+ QSharedPointer<QRingBuffer> outgoingDataBuffer;
+
+ static QNetworkReply::NetworkError statusCodeFromHttp(int httpStatusCode, const QUrl &url);
+ Q_DECLARE_PUBLIC(QNetworkReplyWasmImpl)
+};
+
+QT_END_NAMESPACE
+
+//Q_DECLARE_METATYPE(QNetworkRequest::KnownHeaders)
+
+#endif // QNETWORKREPLYWASMIMPL_H
diff --git a/src/network/configure.json b/src/network/configure.json
index 32fcfb499f..327131ba11 100644
--- a/src/network/configure.json
+++ b/src/network/configure.json
@@ -198,7 +198,7 @@
"label": "OpenSSL",
"enable": "input.openssl == 'yes' || input.openssl == 'linked' || input.openssl == 'runtime'",
"disable": "input.openssl == 'no' || input.ssl == 'no'",
- "autoDetect": "!config.winrt",
+ "autoDetect": "!config.winrt && !config.wasm",
"condition": "!features.securetransport && (features.openssl-linked || libs.openssl_headers)",
"output": [
"privateFeature",
@@ -288,6 +288,7 @@
"networkinterface": {
"label": "QNetworkInterface",
"purpose": "Supports enumerating a host's IP addresses and network interfaces.",
+ "condition": "!config.wasm",
"section": "Networking",
"output": [ "publicFeature", "feature" ]
},
diff --git a/src/network/kernel/qhostinfo_win.cpp b/src/network/kernel/qhostinfo_win.cpp
index bea24b0af2..c51e9968f8 100644
--- a/src/network/kernel/qhostinfo_win.cpp
+++ b/src/network/kernel/qhostinfo_win.cpp
@@ -92,13 +92,13 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
sockaddr *sa;
QT_SOCKLEN_T saSize;
if (address.protocol() == QAbstractSocket::IPv4Protocol) {
- sa = (sockaddr *)&sa4;
+ sa = reinterpret_cast<sockaddr *>(&sa4);
saSize = sizeof(sa4);
memset(&sa4, 0, sizeof(sa4));
sa4.sin_family = AF_INET;
sa4.sin_addr.s_addr = htonl(address.toIPv4Address());
} else {
- sa = (sockaddr *)&sa6;
+ sa = reinterpret_cast<sockaddr *>(&sa6);
saSize = sizeof(sa6);
memset(&sa6, 0, sizeof(sa6));
sa6.sin6_family = AF_INET6;
@@ -132,14 +132,14 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
switch (p->ai_family) {
case AF_INET: {
QHostAddress addr;
- addr.setAddress(ntohl(((sockaddr_in *) p->ai_addr)->sin_addr.s_addr));
+ addr.setAddress(ntohl(reinterpret_cast<sockaddr_in *>(p->ai_addr)->sin_addr.s_addr));
if (!addresses.contains(addr))
addresses.append(addr);
}
break;
case AF_INET6: {
QHostAddress addr;
- addr.setAddress(((sockaddr_in6 *) p->ai_addr)->sin6_addr.s6_addr);
+ addr.setAddress(reinterpret_cast<const sockaddr_in6 *>(p->ai_addr)->sin6_addr.s6_addr);
if (!addresses.contains(addr))
addresses.append(addr);
}
diff --git a/src/network/kernel/qnetworkinterface_win.cpp b/src/network/kernel/qnetworkinterface_win.cpp
index 150553f673..a8d56a9b11 100644
--- a/src/network/kernel/qnetworkinterface_win.cpp
+++ b/src/network/kernel/qnetworkinterface_win.cpp
@@ -74,15 +74,16 @@ static QHostAddress addressFromSockaddr(sockaddr *sa)
if (!sa)
return address;
- if (sa->sa_family == AF_INET)
- address.setAddress(htonl(((sockaddr_in *)sa)->sin_addr.s_addr));
- else if (sa->sa_family == AF_INET6) {
- address.setAddress(((sockaddr_in6 *)sa)->sin6_addr.s6_addr);
- int scope = ((sockaddr_in6 *)sa)->sin6_scope_id;
- if (scope)
- address.setScopeId(QNetworkInterfaceManager::interfaceNameFromIndex(scope));
- } else
+ if (sa->sa_family == AF_INET) {
+ address.setAddress(htonl(reinterpret_cast<const sockaddr_in *>(sa)->sin_addr.s_addr));
+ } else if (sa->sa_family == AF_INET6) {
+ auto sai6 = reinterpret_cast<const sockaddr_in6 *>(sa);
+ address.setAddress(sai6->sin6_addr.s6_addr);
+ if (sai6->sin6_scope_id)
+ address.setScopeId(QNetworkInterfaceManager::interfaceNameFromIndex(sai6->sin6_scope_id));
+ } else {
qWarning("Got unknown socket family %d", sa->sa_family);
+ }
return address;
}
@@ -121,7 +122,7 @@ static QList<QNetworkInterfacePrivate *> interfaceListing()
ULONG retval = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAdapter, &bufSize);
if (retval == ERROR_BUFFER_OVERFLOW) {
// need more memory
- pAdapter = (IP_ADAPTER_ADDRESSES *)malloc(bufSize);
+ pAdapter = reinterpret_cast<IP_ADAPTER_ADDRESSES *>(malloc(bufSize));
if (!pAdapter)
return interfaces;
// try again
@@ -255,7 +256,7 @@ QString QHostInfo::localDomainName()
ULONG bufSize = sizeof info;
pinfo = &info;
if (GetNetworkParams(pinfo, &bufSize) == ERROR_BUFFER_OVERFLOW) {
- pinfo = (FIXED_INFO *)malloc(bufSize);
+ pinfo = reinterpret_cast<FIXED_INFO *>(malloc(bufSize));
if (!pinfo)
return QString();
// try again
diff --git a/src/network/kernel/qnetworkproxy_win.cpp b/src/network/kernel/qnetworkproxy_win.cpp
index 949f9fe12b..e67faaf856 100644
--- a/src/network/kernel/qnetworkproxy_win.cpp
+++ b/src/network/kernel/qnetworkproxy_win.cpp
@@ -566,7 +566,7 @@ void QWindowsSystemProxy::init()
WINHTTP_AUTO_DETECT_TYPE_DNS_A;
} else {
autoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
- autoProxyOptions.lpszAutoConfigUrl = (LPCWSTR)autoConfigUrl.utf16();
+ autoProxyOptions.lpszAutoConfigUrl = reinterpret_cast<LPCWSTR>(autoConfigUrl.utf16());
}
}
@@ -608,7 +608,7 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro
}
bool getProxySucceeded = ptrWinHttpGetProxyForUrl(sp->hHttpSession,
- (LPCWSTR)urlQueryString.utf16(),
+ reinterpret_cast<LPCWSTR>(urlQueryString.utf16()),
&sp->autoProxyOptions,
&proxyInfo);
DWORD getProxyError = GetLastError();
@@ -623,9 +623,10 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro
} else {
//pac file URL is specified as well, try using that
sp->autoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
- sp->autoProxyOptions.lpszAutoConfigUrl = (LPCWSTR)sp->autoConfigUrl.utf16();
+ sp->autoProxyOptions.lpszAutoConfigUrl =
+ reinterpret_cast<LPCWSTR>(sp->autoConfigUrl.utf16());
getProxySucceeded = ptrWinHttpGetProxyForUrl(sp->hHttpSession,
- (LPCWSTR)urlQueryString.utf16(),
+ reinterpret_cast<LPCWSTR>(urlQueryString.utf16()),
&sp->autoProxyOptions,
&proxyInfo);
getProxyError = GetLastError();
@@ -638,7 +639,7 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro
// But now we've to enable it (http://msdn.microsoft.com/en-us/library/aa383153%28v=VS.85%29.aspx)
sp->autoProxyOptions.fAutoLogonIfChallenged = TRUE;
getProxySucceeded = ptrWinHttpGetProxyForUrl(sp->hHttpSession,
- (LPCWSTR)urlQueryString.utf16(),
+ reinterpret_cast<LPCWSTR>(urlQueryString.utf16()),
&sp->autoProxyOptions,
&proxyInfo);
getProxyError = GetLastError();
diff --git a/src/network/socket/qlocalserver_win.cpp b/src/network/socket/qlocalserver_win.cpp
index ced923ced1..2d71a7e730 100644
--- a/src/network/socket/qlocalserver_win.cpp
+++ b/src/network/socket/qlocalserver_win.cpp
@@ -89,7 +89,7 @@ bool QLocalServerPrivate::addListener()
DWORD dwBufferSize = 0;
GetTokenInformation(hToken, TokenUser, 0, 0, &dwBufferSize);
tokenUserBuffer.fill(0, dwBufferSize);
- PTOKEN_USER pTokenUser = (PTOKEN_USER)tokenUserBuffer.data();
+ auto pTokenUser = reinterpret_cast<PTOKEN_USER>(tokenUserBuffer.data());
if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwBufferSize, &dwBufferSize)) {
setError(QLatin1String("QLocalServerPrivate::addListener"));
CloseHandle(hToken);
@@ -99,7 +99,7 @@ bool QLocalServerPrivate::addListener()
dwBufferSize = 0;
GetTokenInformation(hToken, TokenPrimaryGroup, 0, 0, &dwBufferSize);
tokenGroupBuffer.fill(0, dwBufferSize);
- PTOKEN_PRIMARY_GROUP pTokenGroup = (PTOKEN_PRIMARY_GROUP)tokenGroupBuffer.data();
+ auto pTokenGroup = reinterpret_cast<PTOKEN_PRIMARY_GROUP>(tokenGroupBuffer.data());
if (!GetTokenInformation(hToken, TokenPrimaryGroup, pTokenGroup, dwBufferSize, &dwBufferSize)) {
setError(QLatin1String("QLocalServerPrivate::addListener"));
CloseHandle(hToken);
@@ -140,7 +140,7 @@ bool QLocalServerPrivate::addListener()
aclSize = (aclSize + (sizeof(DWORD) - 1)) & 0xfffffffc;
aclBuffer.fill(0, aclSize);
- PACL acl = (PACL)aclBuffer.data();
+ auto acl = reinterpret_cast<PACL>(aclBuffer.data());
InitializeAcl(acl, aclSize, ACL_REVISION_DS);
if (socketOptions & QLocalServer::UserAccessOption) {
@@ -176,7 +176,7 @@ bool QLocalServerPrivate::addListener()
}
listener.handle = CreateNamedPipe(
- (const wchar_t *)fullServerName.utf16(), // pipe name
+ reinterpret_cast<const wchar_t *>(fullServerName.utf16()), // pipe name
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access
PIPE_TYPE_BYTE | // byte type pipe
PIPE_READMODE_BYTE | // byte-read mode
@@ -299,7 +299,7 @@ void QLocalServerPrivate::_q_onNewConnection()
tryAgain = true;
// Make this the last thing so connected slots can wreak the least havoc
- q->incomingConnection((quintptr)handle);
+ q->incomingConnection(reinterpret_cast<quintptr>(handle));
} else {
if (GetLastError() != ERROR_IO_INCOMPLETE) {
q->close();
diff --git a/src/network/socket/qlocalsocket_win.cpp b/src/network/socket/qlocalsocket_win.cpp
index ae94cb9d51..8e20f9efbe 100644
--- a/src/network/socket/qlocalsocket_win.cpp
+++ b/src/network/socket/qlocalsocket_win.cpp
@@ -155,7 +155,7 @@ void QLocalSocket::connectToServer(OpenMode openMode)
forever {
DWORD permissions = (openMode & QIODevice::ReadOnly) ? GENERIC_READ : 0;
permissions |= (openMode & QIODevice::WriteOnly) ? GENERIC_WRITE : 0;
- localSocket = CreateFile((const wchar_t *)d->fullServerName.utf16(), // pipe name
+ localSocket = CreateFile(reinterpret_cast<const wchar_t *>(d->fullServerName.utf16()), // pipe name
permissions,
0, // no sharing
NULL, // default security attributes
@@ -183,7 +183,7 @@ void QLocalSocket::connectToServer(OpenMode openMode)
}
// we have a valid handle
- if (setSocketDescriptor((qintptr)localSocket, ConnectedState, openMode))
+ if (setSocketDescriptor(reinterpret_cast<qintptr>(localSocket), ConnectedState, openMode))
emit connected();
}
@@ -371,7 +371,7 @@ void QLocalSocketPrivate::_q_canWrite()
qintptr QLocalSocket::socketDescriptor() const
{
Q_D(const QLocalSocket);
- return (qintptr)d->handle;
+ return reinterpret_cast<qintptr>(d->handle);
}
qint64 QLocalSocket::readBufferSize() const
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp
index 1b84b26d83..c999bd2088 100644
--- a/src/network/socket/qnativesocketengine_win.cpp
+++ b/src/network/socket/qnativesocketengine_win.cpp
@@ -294,7 +294,8 @@ static inline QAbstractSocket::SocketType qt_socket_getType(qintptr socketDescri
{
int value = 0;
QT_SOCKLEN_T valueSize = sizeof(value);
- if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_TYPE, (char *) &value, &valueSize) != 0) {
+ if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_TYPE,
+ reinterpret_cast<char *>(&value), &valueSize) != 0) {
WS_ERROR_DEBUG(WSAGetLastError());
} else {
if (value == SOCK_STREAM)
@@ -361,7 +362,7 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc
#ifdef HANDLE_FLAG_INHERIT
if (socket != INVALID_SOCKET) {
// make non inheritable the old way
- BOOL handleFlags = SetHandleInformation((HANDLE)socket, HANDLE_FLAG_INHERIT, 0);
+ BOOL handleFlags = SetHandleInformation(reinterpret_cast<HANDLE>(socket), HANDLE_FLAG_INHERIT, 0);
#ifdef QNATIVESOCKETENGINE_DEBUG
qDebug() << "QNativeSocketEnginePrivate::createNewSocket - set inheritable" << handleFlags;
#else
@@ -1443,7 +1444,7 @@ qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len)
for (;;) {
WSABUF buf;
- buf.buf = (char*)data + ret;
+ buf.buf = const_cast<char*>(data) + ret;
buf.len = bytesToSend;
DWORD flags = 0;
DWORD bytesWritten = 0;
diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp
index 0b386ededc..0b2ddf97fe 100644
--- a/src/opengl/qglframebufferobject.cpp
+++ b/src/opengl/qglframebufferobject.cpp
@@ -103,6 +103,14 @@ extern QImage qt_gl_read_frame_buffer(const QSize&, bool, bool);
#define GL_DRAW_FRAMEBUFFER 0x8CA9
#endif
+#ifndef GL_DEPTH_STENCIL_ATTACHMENT
+#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
+#endif
+
+#ifndef GL_DEPTH_STENCIL
+#define GL_DEPTH_STENCIL 0x84F9
+#endif
+
/*!
\class QGLFramebufferObjectFormat
\inmodule QtOpenGL
@@ -562,6 +570,7 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
funcs.glGenRenderbuffers(1, &depth_buffer);
funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer));
+#ifndef Q_OS_WASM
if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample))
funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
GL_DEPTH24_STENCIL8, size.width(), size.height());
@@ -574,6 +583,19 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
GL_RENDERBUFFER, depth_buffer);
funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, stencil_buffer);
+#else
+ // webgl does not allow separate depth and stencil attachments
+ if (samples != 0) {
+ funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
+ GL_DEPTH_STENCIL, size.width(), size.height());
+ } else {
+ funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL,
+ size.width(), size.height());
+ }
+ stencil_buffer = depth_buffer;
+ funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
+ GL_RENDERBUFFER, depth_buffer);
+#endif
valid = checkFramebufferStatus();
if (!valid) {
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
index 890792fa2f..6b86f01616 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
@@ -1608,7 +1608,8 @@ void QWindowsFontDatabase::removeApplicationFonts()
if (font.handle) {
RemoveFontMemResourceEx(font.handle);
} else {
- RemoveFontResourceExW((LPCWSTR)font.fileName.utf16(), FR_PRIVATE, 0);
+ RemoveFontResourceExW(reinterpret_cast<LPCWSTR>(font.fileName.utf16()),
+ FR_PRIVATE, nullptr);
}
}
m_applicationFonts.clear();
@@ -1652,7 +1653,8 @@ void QWindowsFontDatabase::refUniqueFont(const QString &uniqueFont)
// ### fixme Qt 6 (QTBUG-58610): See comment at QWindowsFontDatabase::systemDefaultFont()
HFONT QWindowsFontDatabase::systemFont()
{
- static const HFONT stock_sysfont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
+ static const auto stock_sysfont =
+ reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT));
return stock_sysfont;
}
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp
index 584e4db05d..2a41209225 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp
@@ -111,9 +111,8 @@ QFixed QWindowsFontEngine::lineThickness() const
static OUTLINETEXTMETRIC *getOutlineTextMetric(HDC hdc)
{
- int size;
- size = GetOutlineTextMetrics(hdc, 0, 0);
- OUTLINETEXTMETRIC *otm = (OUTLINETEXTMETRIC *)malloc(size);
+ const auto size = GetOutlineTextMetrics(hdc, 0, nullptr);
+ auto otm = reinterpret_cast<OUTLINETEXTMETRIC *>(malloc(size));
GetOutlineTextMetrics(hdc, size, otm);
return otm;
}
@@ -1140,7 +1139,7 @@ QImage QWindowsFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed, const QTra
QImage rgbMask(mask->width(), mask->height(), QImage::Format_RGB32);
for (int y=0; y<mask->height(); ++y) {
- uint *dest = (uint *) rgbMask.scanLine(y);
+ auto dest = reinterpret_cast<uint *>(rgbMask.scanLine(y));
const uint *src = reinterpret_cast<const uint *>(source.constScanLine(y));
for (int x=0; x<mask->width(); ++x) {
dest[x] = 0xffffffff - (0x00ffffff & src[x]);
diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.mm b/src/plugins/platforms/cocoa/qcocoaapplication.mm
index 11f3bd0384..340191622a 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplication.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplication.mm
@@ -116,8 +116,8 @@ static bool qt_filterEvent(NSEvent *event)
filterNativeEvent(q_macLocalEventType, static_cast<void*>(event), nullptr))
return true;
- if ([event type] == NSApplicationDefined) {
- switch (static_cast<short>([event subtype])) {
+ if (event.type == NSEventTypeApplicationDefined) {
+ switch (static_cast<short>(event.subtype)) {
case QtCocoaEventSubTypePostMessage:
qt_sendPostedMessage(event);
return true;
@@ -137,7 +137,7 @@ static void qt_maybeSendKeyEquivalentUpEvent(NSEvent *event)
// and forward the key event to the key (focus) window.
// However, non-Qt windows will not (and should not) get
// any special treatment, only QWindow-owned NSWindows.
- if (event.type == NSKeyUp && (event.modifierFlags & NSCommandKeyMask)) {
+ if (event.type == NSEventTypeKeyUp && (event.modifierFlags & NSEventModifierFlagCommand)) {
NSWindow *targetWindow = event.window;
if ([targetWindow.class conformsToProtocol:@protocol(QNSWindowProtocol)])
[targetWindow sendEvent:event];
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
index 7601fb7e17..221a8b0866 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
@@ -267,13 +267,11 @@ QT_USE_NAMESPACE
inLaunch = false;
if (qEnvironmentVariableIsEmpty("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM")) {
- if (__builtin_available(macOS 10.12, *)) {
- // Move the application window to front to avoid launching behind the terminal.
- // Ignoring other apps is necessary (we must ignore the terminal), but makes
- // Qt apps play slightly less nice with other apps when lanching from Finder
- // (See the activateIgnoringOtherApps docs.)
- [[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
- }
+ // Move the application window to front to avoid launching behind the terminal.
+ // Ignoring other apps is necessary (we must ignore the terminal), but makes
+ // Qt apps play slightly less nice with other apps when lanching from Finder
+ // (See the activateIgnoringOtherApps docs.)
+ [[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
}
}
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
index 13b4e2ecd1..81a0a7d040 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
@@ -67,11 +67,6 @@ QImage::Format QCocoaBackingStore::format() const
return QRasterBackingStore::format();
}
-#if !QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_12)
-static const NSCompositingOperation NSCompositingOperationCopy = NSCompositeCopy;
-static const NSCompositingOperation NSCompositingOperationSourceOver = NSCompositeSourceOver;
-#endif
-
/*!
Flushes the given \a region from the specified \a window onto the
screen.
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
index 611853642a..2a41498564 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
@@ -293,25 +293,25 @@ static bool IsMouseOrKeyEvent( NSEvent* event )
switch( [event type] )
{
- case NSLeftMouseDown:
- case NSLeftMouseUp:
- case NSRightMouseDown:
- case NSRightMouseUp:
- case NSMouseMoved: // ??
- case NSLeftMouseDragged:
- case NSRightMouseDragged:
- case NSMouseEntered:
- case NSMouseExited:
- case NSKeyDown:
- case NSKeyUp:
- case NSFlagsChanged: // key modifiers changed?
- case NSCursorUpdate: // ??
- case NSScrollWheel:
- case NSTabletPoint:
- case NSTabletProximity:
- case NSOtherMouseDown:
- case NSOtherMouseUp:
- case NSOtherMouseDragged:
+ case NSEventTypeLeftMouseDown:
+ case NSEventTypeLeftMouseUp:
+ case NSEventTypeRightMouseDown:
+ case NSEventTypeRightMouseUp:
+ case NSEventTypeMouseMoved: // ??
+ case NSEventTypeLeftMouseDragged:
+ case NSEventTypeRightMouseDragged:
+ case NSEventTypeMouseEntered:
+ case NSEventTypeMouseExited:
+ case NSEventTypeKeyDown:
+ case NSEventTypeKeyUp:
+ case NSEventTypeFlagsChanged: // key modifiers changed?
+ case NSEventTypeCursorUpdate: // ??
+ case NSEventTypeScrollWheel:
+ case NSEventTypeTabletPoint:
+ case NSEventTypeTabletProximity:
+ case NSEventTypeOtherMouseDown:
+ case NSEventTypeOtherMouseUp:
+ case NSEventTypeOtherMouseDragged:
#ifndef QT_NO_GESTURES
case NSEventTypeGesture: // touch events
case NSEventTypeMagnify:
@@ -335,7 +335,7 @@ static inline void qt_mac_waitForMoreEvents(NSString *runLoopMode = NSDefaultRun
// at least one event occur. Setting 'dequeuing' to 'no' in the following call
// causes it to hang under certain circumstances (QTBUG-28283), so we tell it
// to dequeue instead, just to repost the event again:
- NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:[NSDate distantFuture]
inMode:runLoopMode
dequeue:YES];
@@ -460,7 +460,7 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
// Dispatch all non-user events (but que non-user events up for later). In
// this case, we need more control over which events gets dispatched, and
// cannot use [NSApp runModalSession:session]:
- event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:nil
inMode:NSModalPanelRunLoopMode
dequeue: YES];
@@ -479,7 +479,7 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
} while (!d->interrupt && event);
} else do {
// INVARIANT: No modal window is executing.
- event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:nil
inMode:NSDefaultRunLoopMode
dequeue: YES];
@@ -936,7 +936,7 @@ void QCocoaEventDispatcherPrivate::cancelWaitForMoreEvents()
// In case the event dispatcher is waiting for more
// events somewhere, we post a dummy event to wake it up:
QMacAutoReleasePool pool;
- [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined location:NSZeroPoint
+ [NSApp postEvent:[NSEvent otherEventWithType:NSEventTypeApplicationDefined location:NSZeroPoint
modifierFlags:0 timestamp:0. windowNumber:0 context:nil
subtype:QtCocoaEventSubTypeWakeup data1:0 data2:0] atStart:NO];
}
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
index dcc57daf11..e7243ec250 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
@@ -515,8 +515,8 @@ static QString strippedText(QString s)
NSRect textRect = { { 0.0, 3.0 }, { 100.0, 25.0 } };
mTextField = [[NSTextField alloc] initWithFrame:textRect];
[[mTextField cell] setFont:[NSFont systemFontOfSize:
- [NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
- [mTextField setAlignment:NSRightTextAlignment];
+ [NSFont systemFontSizeForControlSize:NSControlSizeRegular]]];
+ [mTextField setAlignment:NSTextAlignmentRight];
[mTextField setEditable:false];
[mTextField setSelectable:false];
[mTextField setBordered:false];
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
index 4d0fa2e28e..c23636a1a0 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
@@ -217,9 +217,6 @@ NSOpenGLPixelFormat *QCocoaGLContext::pixelFormatForSurfaceFormat(const QSurface
<< NSOpenGLPFASamples << NSOpenGLPixelFormatAttribute(format.samples());
}
- if (format.stereo())
- attrs << NSOpenGLPFAStereo;
-
// Allow rendering on GPUs without a connected display
attrs << NSOpenGLPFAAllowOfflineRenderers;
@@ -277,6 +274,9 @@ void QCocoaGLContext::updateSurfaceFormat()
// Debug contexts not supported on macOS
m_format.setOption(QSurfaceFormat::DebugContext, false);
+ // Nor are stereo buffers (deprecated in macOS 10.12)
+ m_format.setOption(QSurfaceFormat::StereoBuffers, false);
+
// ------------------ Query the pixel format ------------------
NSOpenGLPixelFormat *pixelFormat = m_context.pixelFormat;
@@ -306,8 +306,6 @@ void QCocoaGLContext::updateSurfaceFormat()
else
m_format.setSwapBehavior(QSurfaceFormat::SingleBuffer);
- m_format.setOption(QSurfaceFormat::StereoBuffers, [pixelFormat qt_getAttribute:NSOpenGLPFAStereo]);
-
// ------------------- Query the context -------------------
m_format.setSwapInterval([m_context qt_getParameter:NSOpenGLCPSwapInterval]);
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
index c7ddd8458d..0f5ddfa49a 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -295,12 +295,12 @@ Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum)
Qt::MouseButton cocoaButton2QtButton(NSEvent *event)
{
switch (event.type) {
- case NSMouseMoved:
+ case NSEventTypeMouseMoved:
return Qt::NoButton;
- case NSRightMouseUp:
- case NSRightMouseDown:
- case NSRightMouseDragged:
+ case NSEventTypeRightMouseUp:
+ case NSEventTypeRightMouseDown:
+ case NSEventTypeRightMouseDragged:
return Qt::RightButton;
default:
@@ -318,22 +318,22 @@ Qt::MouseButton cocoaButton2QtButton(NSEvent *event)
QEvent::Type cocoaEvent2QtMouseEvent(NSEvent *event)
{
switch (event.type) {
- case NSLeftMouseDown:
- case NSRightMouseDown:
- case NSOtherMouseDown:
+ case NSEventTypeLeftMouseDown:
+ case NSEventTypeRightMouseDown:
+ case NSEventTypeOtherMouseDown:
return QEvent::MouseButtonPress;
- case NSLeftMouseUp:
- case NSRightMouseUp:
- case NSOtherMouseUp:
+ case NSEventTypeLeftMouseUp:
+ case NSEventTypeRightMouseUp:
+ case NSEventTypeOtherMouseUp:
return QEvent::MouseButtonRelease;
- case NSLeftMouseDragged:
- case NSRightMouseDragged:
- case NSOtherMouseDragged:
+ case NSEventTypeLeftMouseDragged:
+ case NSEventTypeRightMouseDragged:
+ case NSEventTypeOtherMouseDragged:
return QEvent::MouseMove;
- case NSMouseMoved:
+ case NSEventTypeMouseMoved:
return QEvent::MouseMove;
default:
@@ -432,7 +432,7 @@ QT_END_NAMESPACE
// FIXME: Not obvious, from Cocoa's documentation, that QString::toNSString() makes a deep copy
button.title = (NSString *)cleanTitle.toCFString();
((NSButtonCell *)button.cell).font =
- [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]];
+ [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSControlSizeRegular]];
[self addSubview:button];
return button;
}
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index 90e90b32b6..7b96fca3f9 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -391,7 +391,7 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
if (view) {
// Finally, we need to synthesize an event.
- NSEvent *menuEvent = [NSEvent mouseEventWithType:NSRightMouseDown
+ NSEvent *menuEvent = [NSEvent mouseEventWithType:NSEventTypeRightMouseDown
location:nsPos
modifierFlags:0
timestamp:0
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
index e1572e1800..21faa6d985 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
@@ -61,13 +61,13 @@ static quint32 constructModifierMask(quint32 accel_key)
quint32 ret = 0;
const bool dontSwap = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta);
if ((accel_key & Qt::CTRL) == Qt::CTRL)
- ret |= (dontSwap ? NSControlKeyMask : NSCommandKeyMask);
+ ret |= (dontSwap ? NSEventModifierFlagControl : NSEventModifierFlagCommand);
if ((accel_key & Qt::META) == Qt::META)
- ret |= (dontSwap ? NSCommandKeyMask : NSControlKeyMask);
+ ret |= (dontSwap ? NSEventModifierFlagCommand : NSEventModifierFlagControl);
if ((accel_key & Qt::ALT) == Qt::ALT)
- ret |= NSAlternateKeyMask;
+ ret |= NSEventModifierFlagOption;
if ((accel_key & Qt::SHIFT) == Qt::SHIFT)
- ret |= NSShiftKeyMask;
+ ret |= NSEventModifierFlagShift;
return ret;
}
@@ -343,7 +343,7 @@ NSMenuItem *QCocoaMenuItem::sync()
#endif
{
m_native.keyEquivalent = @"";
- m_native.keyEquivalentModifierMask = NSCommandKeyMask;
+ m_native.keyEquivalentModifierMask = NSEventModifierFlagCommand;
}
NSImage *img = nil;
diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
index 5610c36ea1..da0fc5c6a1 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuloader.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
@@ -155,7 +155,7 @@
action:@selector(hideOtherApplications:)
keyEquivalent:@"h"];
hideAllOthersItem.target = self;
- hideAllOthersItem.keyEquivalentModifierMask = NSCommandKeyMask | NSAlternateKeyMask;
+ hideAllOthersItem.keyEquivalentModifierMask = NSEventModifierFlagCommand | NSEventModifierFlagOption;
[appMenu addItem:hideAllOthersItem];
// Show All
diff --git a/src/plugins/platforms/cocoa/qcocoansmenu.mm b/src/plugins/platforms/cocoa/qcocoansmenu.mm
index 752f38d68d..65b0832d9f 100644
--- a/src/plugins/platforms/cocoa/qcocoansmenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoansmenu.mm
@@ -225,7 +225,8 @@ static NSString *qt_mac_removePrivateUnicode(NSString *string)
CHECK_MENU_CLASS(menu);
// Interested only in Shift, Cmd, Ctrl & Alt Keys, so ignoring masks like, Caps lock, Num Lock ...
- static const NSUInteger mask = NSShiftKeyMask | NSControlKeyMask | NSCommandKeyMask | NSAlternateKeyMask;
+ static const NSUInteger mask = NSEventModifierFlagShift | NSEventModifierFlagControl
+ | NSEventModifierFlagCommand | NSEventModifierFlagOption;
// Change the private unicode keys to the ones used in setting the "Key Equivalents"
NSString *characters = qt_mac_removePrivateUnicode(event.charactersIgnoringModifiers);
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 3148501006..2178f3bf23 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -337,9 +337,9 @@ void QCocoaWindow::setVisible(bool visible)
// Since this isn't a native popup, the window manager doesn't close the popup when you click outside
NSWindow *nativeParentWindow = parentCocoaWindow->nativeWindow();
NSUInteger parentStyleMask = nativeParentWindow.styleMask;
- if ((m_resizableTransientParent = (parentStyleMask & NSResizableWindowMask))
- && !(nativeParentWindow.styleMask & NSFullScreenWindowMask))
- nativeParentWindow.styleMask &= ~NSResizableWindowMask;
+ if ((m_resizableTransientParent = (parentStyleMask & NSWindowStyleMaskResizable))
+ && !(nativeParentWindow.styleMask & NSWindowStyleMaskFullScreen))
+ nativeParentWindow.styleMask &= ~NSWindowStyleMaskResizable;
}
}
@@ -384,7 +384,9 @@ void QCocoaWindow::setVisible(bool visible)
((NSPanel *)m_view.window).worksWhenModal = YES;
if (!(parentCocoaWindow && window()->transientParent()->isActive()) && window()->type() == Qt::Popup) {
removeMonitor();
- monitor = [NSEvent addGlobalMonitorForEventsMatchingMask:NSLeftMouseDownMask|NSRightMouseDownMask|NSOtherMouseDownMask|NSMouseMovedMask handler:^(NSEvent *e) {
+ NSEventMask eventMask = NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown
+ | NSEventMaskOtherMouseDown | NSEventMaskMouseMoved;
+ monitor = [NSEvent addGlobalMonitorForEventsMatchingMask:eventMask handler:^(NSEvent *e) {
const auto button = cocoaButton2QtButton(e);
const auto buttons = currentlyPressedMouseButtons();
const auto eventType = cocoaEvent2QtMouseEvent(e);
@@ -446,9 +448,9 @@ void QCocoaWindow::setVisible(bool visible)
if (parentCocoaWindow && window()->type() == Qt::Popup) {
NSWindow *nativeParentWindow = parentCocoaWindow->nativeWindow();
if (m_resizableTransientParent
- && !(nativeParentWindow.styleMask & NSFullScreenWindowMask))
+ && !(nativeParentWindow.styleMask & NSWindowStyleMaskFullScreen))
// A window should not be resizable while a transient popup is open
- nativeParentWindow.styleMask |= NSResizableWindowMask;
+ nativeParentWindow.styleMask |= NSWindowStyleMaskResizable;
}
}
@@ -491,39 +493,39 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags)
const bool frameless = (flags & Qt::FramelessWindowHint) || windowIsPopupType(type);
// Remove zoom button by disabling resize for CustomizeWindowHint windows, except for
- // Qt::Tool windows (e.g. dock windows) which should always be resizeable.
- const bool resizeable = !(flags & Qt::CustomizeWindowHint) || (type == Qt::Tool);
+ // Qt::Tool windows (e.g. dock windows) which should always be resizable.
+ const bool resizable = !(flags & Qt::CustomizeWindowHint) || (type == Qt::Tool);
// Select base window type. Note that the value of NSBorderlessWindowMask is 0.
- NSUInteger styleMask = (frameless || !resizeable) ? NSBorderlessWindowMask : NSResizableWindowMask;
+ NSUInteger styleMask = (frameless || !resizable) ? NSWindowStyleMaskBorderless : NSWindowStyleMaskResizable;
if (frameless) {
// No further customizations for frameless since there are no window decorations.
} else if (flags & Qt::CustomizeWindowHint) {
if (flags & Qt::WindowTitleHint)
- styleMask |= NSTitledWindowMask;
+ styleMask |= NSWindowStyleMaskTitled;
if (flags & Qt::WindowCloseButtonHint)
- styleMask |= NSClosableWindowMask;
+ styleMask |= NSWindowStyleMaskClosable;
if (flags & Qt::WindowMinimizeButtonHint)
- styleMask |= NSMiniaturizableWindowMask;
+ styleMask |= NSWindowStyleMaskMiniaturizable;
if (flags & Qt::WindowMaximizeButtonHint)
- styleMask |= NSResizableWindowMask;
+ styleMask |= NSWindowStyleMaskResizable;
} else {
- styleMask |= NSClosableWindowMask | NSTitledWindowMask;
+ styleMask |= NSWindowStyleMaskClosable | NSWindowStyleMaskTitled;
if (type != Qt::Dialog)
- styleMask |= NSMiniaturizableWindowMask;
+ styleMask |= NSWindowStyleMaskMiniaturizable;
}
if (type == Qt::Tool)
- styleMask |= NSUtilityWindowMask;
+ styleMask |= NSWindowStyleMaskUtilityWindow;
if (m_drawContentBorderGradient)
- styleMask |= NSTexturedBackgroundWindowMask;
+ styleMask |= NSWindowStyleMaskTexturedBackground;
// Don't wipe fullscreen state
- if (m_view.window.styleMask & NSFullScreenWindowMask)
- styleMask |= NSFullScreenWindowMask;
+ if (m_view.window.styleMask & NSWindowStyleMaskFullScreen)
+ styleMask |= NSWindowStyleMaskFullScreen;
return styleMask;
}
@@ -630,7 +632,7 @@ void QCocoaWindow::applyWindowState(Qt::WindowStates requestedState)
const NSWindow *nsWindow = m_view.window;
- if (nsWindow.styleMask & NSUtilityWindowMask
+ if (nsWindow.styleMask & NSWindowStyleMaskUtilityWindow
&& newState & (Qt::WindowMinimized | Qt::WindowFullScreen)) {
qWarning() << window()->type() << "windows can not be made" << newState;
handleWindowStateChanged(HandleUnconditionally);
@@ -704,14 +706,14 @@ void QCocoaWindow::toggleMaximized()
// The NSWindow needs to be resizable, otherwise the window will
// not be possible to zoom back to non-zoomed state.
- const bool wasResizable = window.styleMask & NSResizableWindowMask;
- window.styleMask |= NSResizableWindowMask;
+ const bool wasResizable = window.styleMask & NSWindowStyleMaskResizable;
+ window.styleMask |= NSWindowStyleMaskResizable;
const id sender = window;
[window zoom:sender];
if (!wasResizable)
- window.styleMask &= ~NSResizableWindowMask;
+ window.styleMask &= ~NSWindowStyleMaskResizable;
}
void QCocoaWindow::toggleFullScreen()
@@ -735,13 +737,13 @@ void QCocoaWindow::windowWillEnterFullScreen()
// The NSWindow needs to be resizable, otherwise we'll end up with
// the normal window geometry, centered in the middle of the screen
// on a black background. The styleMask will be reset below.
- m_view.window.styleMask |= NSResizableWindowMask;
+ m_view.window.styleMask |= NSWindowStyleMaskResizable;
}
bool QCocoaWindow::isTransitioningToFullScreen() const
{
NSWindow *window = m_view.window;
- return window.styleMask & NSFullScreenWindowMask && !window.qt_fullScreen;
+ return window.styleMask & NSWindowStyleMaskFullScreen && !window.qt_fullScreen;
}
void QCocoaWindow::windowDidEnterFullScreen()
@@ -765,7 +767,7 @@ void QCocoaWindow::windowWillExitFullScreen()
// The NSWindow needs to be resizable, otherwise we'll end up with
// a weird zoom animation. The styleMask will be reset below.
- m_view.window.styleMask |= NSResizableWindowMask;
+ m_view.window.styleMask |= NSWindowStyleMaskResizable;
}
void QCocoaWindow::windowDidExitFullScreen()
@@ -1707,7 +1709,7 @@ void QCocoaWindow::applyContentBorderThickness(NSWindow *window)
return;
if (!m_drawContentBorderGradient) {
- window.styleMask = window.styleMask & ~NSTexturedBackgroundWindowMask;
+ window.styleMask = window.styleMask & ~NSWindowStyleMaskTexturedBackground;
[window.contentView.superview setNeedsDisplay:YES];
window.titlebarAppearsTransparent = NO;
return;
@@ -1733,7 +1735,7 @@ void QCocoaWindow::applyContentBorderThickness(NSWindow *window)
int effectiveBottomContentBorderThickness = m_bottomContentBorderThickness;
- [window setStyleMask:[window styleMask] | NSTexturedBackgroundWindowMask];
+ [window setStyleMask:[window styleMask] | NSWindowStyleMaskTexturedBackground];
window.titlebarAppearsTransparent = YES;
[window setContentBorderThickness:effectiveTopContentBorderThickness forEdge:NSMaxYEdge];
diff --git a/src/plugins/platforms/cocoa/qnsview_keys.mm b/src/plugins/platforms/cocoa/qnsview_keys.mm
index 57ce6a009f..85c0607265 100644
--- a/src/plugins/platforms/cocoa/qnsview_keys.mm
+++ b/src/plugins/platforms/cocoa/qnsview_keys.mm
@@ -45,15 +45,15 @@
{
const bool dontSwapCtrlAndMeta = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta);
Qt::KeyboardModifiers qtMods =Qt::NoModifier;
- if (modifierFlags & NSShiftKeyMask)
+ if (modifierFlags & NSEventModifierFlagShift)
qtMods |= Qt::ShiftModifier;
- if (modifierFlags & NSControlKeyMask)
+ if (modifierFlags & NSEventModifierFlagShift)
qtMods |= dontSwapCtrlAndMeta ? Qt::ControlModifier : Qt::MetaModifier;
- if (modifierFlags & NSAlternateKeyMask)
+ if (modifierFlags & NSEventModifierFlagOption)
qtMods |= Qt::AltModifier;
- if (modifierFlags & NSCommandKeyMask)
+ if (modifierFlags & NSEventModifierFlagCommand)
qtMods |= dontSwapCtrlAndMeta ? Qt::MetaModifier : Qt::ControlModifier;
- if (modifierFlags & NSNumericPadKeyMask)
+ if (modifierFlags & NSEventModifierFlagCommand)
qtMods |= Qt::KeypadModifier;
return qtMods;
}
@@ -201,7 +201,7 @@
Q_UNUSED(sender);
NSEvent *currentEvent = [NSApp currentEvent];
- if (!currentEvent || currentEvent.type != NSKeyDown)
+ if (!currentEvent || currentEvent.type != NSEventTypeKeyDown)
return;
// Handling the key event may recurse back here through interpretKeyEvents
@@ -233,11 +233,11 @@
Qt::Key qt_code;
};
static qt_mac_enum_mapper modifier_key_symbols[] = {
- { NSShiftKeyMask, Qt::Key_Shift },
- { NSControlKeyMask, Qt::Key_Meta },
- { NSCommandKeyMask, Qt::Key_Control },
- { NSAlternateKeyMask, Qt::Key_Alt },
- { NSAlphaShiftKeyMask, Qt::Key_CapsLock },
+ { NSEventModifierFlagShift, Qt::Key_Shift },
+ { NSEventModifierFlagControl, Qt::Key_Meta },
+ { NSEventModifierFlagCommand, Qt::Key_Control },
+ { NSEventModifierFlagOption, Qt::Key_Alt },
+ { NSEventModifierFlagCapsLock, Qt::Key_CapsLock },
{ 0ul, Qt::Key_unknown } };
for (int i = 0; modifier_key_symbols[i].mac_mask != 0u; ++i) {
uint mac_mask = modifier_key_symbols[i].mac_mask;
diff --git a/src/plugins/platforms/cocoa/qnsview_mouse.mm b/src/plugins/platforms/cocoa/qnsview_mouse.mm
index 65bc9f837d..468f26ffb4 100644
--- a/src/plugins/platforms/cocoa/qnsview_mouse.mm
+++ b/src/plugins/platforms/cocoa/qnsview_mouse.mm
@@ -91,31 +91,26 @@
if (m_buttons != Qt::NoButton)
return;
- NSEventType ty = [theEvent type];
- switch (ty) {
- case NSLeftMouseDown:
+ switch (theEvent.type) {
+ case NSEventTypeLeftMouseDown:
+ case NSEventTypeLeftMouseDragged:
m_frameStrutButtons |= Qt::LeftButton;
break;
- case NSLeftMouseUp:
+ case NSEventTypeLeftMouseUp:
m_frameStrutButtons &= ~Qt::LeftButton;
break;
- case NSRightMouseDown:
+ case NSEventTypeRightMouseDown:
+ case NSEventTypeRightMouseDragged:
m_frameStrutButtons |= Qt::RightButton;
break;
- case NSLeftMouseDragged:
- m_frameStrutButtons |= Qt::LeftButton;
- break;
- case NSRightMouseDragged:
- m_frameStrutButtons |= Qt::RightButton;
- break;
- case NSRightMouseUp:
+ case NSEventTypeRightMouseUp:
m_frameStrutButtons &= ~Qt::RightButton;
break;
- case NSOtherMouseDown:
- m_frameStrutButtons |= cocoaButton2QtButton([theEvent buttonNumber]);
+ case NSEventTypeOtherMouseDown:
+ m_frameStrutButtons |= cocoaButton2QtButton(theEvent.buttonNumber);
break;
- case NSOtherMouseUp:
- m_frameStrutButtons &= ~cocoaButton2QtButton([theEvent buttonNumber]);
+ case NSEventTypeOtherMouseUp:
+ m_frameStrutButtons &= ~cocoaButton2QtButton(theEvent.buttonNumber);
default:
break;
}
@@ -581,7 +576,7 @@
// knowing whether or not a NSEventPhaseEnded will be followed by a momentum phase.
// The best we can do is to look at the event queue and hope that the system has
// had time to emit a momentum phase event.
- if ([NSApp nextEventMatchingMask:NSScrollWheelMask untilDate:[NSDate distantPast]
+ if ([NSApp nextEventMatchingMask:NSEventMaskScrollWheel untilDate:[NSDate distantPast]
inMode:@"QtMomementumEventSearchMode" dequeue:NO].momentumPhase == NSEventPhaseBegan) {
Q_ASSERT(pixelDelta.isNull() && angleDelta.isNull());
return; // Ignore this event, as it has a delta of 0,0
diff --git a/src/plugins/platforms/cocoa/qnsview_tablet.mm b/src/plugins/platforms/cocoa/qnsview_tablet.mm
index 0b56123955..43b0aa0960 100644
--- a/src/plugins/platforms/cocoa/qnsview_tablet.mm
+++ b/src/plugins/platforms/cocoa/qnsview_tablet.mm
@@ -64,7 +64,7 @@ Q_GLOBAL_STATIC(QCocoaTabletDeviceDataHash, tabletDeviceDataHash)
return false;
NSEventType eventType = [theEvent type];
- if (eventType != NSTabletPoint && [theEvent subtype] != NSTabletPointEventSubtype)
+ if (eventType != NSEventTypeTabletPoint && [theEvent subtype] != NSEventSubtypeTabletPoint)
return false; // Not a tablet event.
ulong timestamp = [theEvent timestamp] * 1000;
@@ -82,7 +82,7 @@ Q_GLOBAL_STATIC(QCocoaTabletDeviceDataHash, tabletDeviceDataHash)
}
const QCocoaTabletDeviceData &deviceData = tabletDeviceDataHash->value(deviceId);
- bool down = (eventType != NSMouseMoved);
+ bool down = (eventType != NSEventTypeMouseMoved);
qreal pressure;
if (down) {
@@ -182,17 +182,17 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
deviceData.capabilityMask = [theEvent capabilityMask];
switch ([theEvent pointingDeviceType]) {
- case NSUnknownPointingDevice:
+ case NSPointingDeviceTypeUnknown:
default:
deviceData.pointerType = QTabletEvent::UnknownPointer;
break;
- case NSPenPointingDevice:
+ case NSPointingDeviceTypePen:
deviceData.pointerType = QTabletEvent::Pen;
break;
- case NSCursorPointingDevice:
+ case NSPointingDeviceTypeCursor:
deviceData.pointerType = QTabletEvent::Cursor;
break;
- case NSEraserPointingDevice:
+ case NSPointingDeviceTypeEraser:
deviceData.pointerType = QTabletEvent::Eraser;
break;
}
diff --git a/src/plugins/platforms/cocoa/qnswindow.mm b/src/plugins/platforms/cocoa/qnswindow.mm
index c959fdd917..1b9dd95cbc 100644
--- a/src/plugins/platforms/cocoa/qnswindow.mm
+++ b/src/plugins/platforms/cocoa/qnswindow.mm
@@ -50,13 +50,13 @@ Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events");
static bool isMouseEvent(NSEvent *ev)
{
switch ([ev type]) {
- case NSLeftMouseDown:
- case NSLeftMouseUp:
- case NSRightMouseDown:
- case NSRightMouseUp:
- case NSMouseMoved:
- case NSLeftMouseDragged:
- case NSRightMouseDragged:
+ case NSEventTypeLeftMouseDown:
+ case NSEventTypeLeftMouseUp:
+ case NSEventTypeRightMouseDown:
+ case NSEventTypeRightMouseUp:
+ case NSEventTypeMouseMoved:
+ case NSEventTypeLeftMouseDragged:
+ case NSEventTypeRightMouseDragged:
return true;
default:
return false;
@@ -186,16 +186,16 @@ static bool isMouseEvent(NSEvent *ev)
/*!
Borderless windows need a transparent background
- Technically windows with NSTexturedBackgroundWindowMask (such
- as windows with unified toolbars) need to draw the textured
+ Technically windows with NSWindowStyleMaskTexturedBackground
+ (such as windows with unified toolbars) need to draw the textured
background of the NSWindow, and can't have a transparent
- background, but as NSBorderlessWindowMask is 0, you can't
- have a window with NSTexturedBackgroundWindowMask that is
+ background, but as NSWindowStyleMaskBorderless is 0, you can't
+ have a window with NSWindowStyleMaskTexturedBackground that is
also borderless.
*/
- (NSColor *)backgroundColor
{
- return self.styleMask == NSBorderlessWindowMask
+ return self.styleMask == NSWindowStyleMaskBorderless
? [NSColor clearColor] : qt_objcDynamicSuper();
}
@@ -262,29 +262,20 @@ static bool isMouseEvent(NSEvent *ev)
NSEnumerator<NSWindow*> *windowEnumerator = nullptr;
NSApplication *application = [NSApplication sharedApplication];
-#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_12)
- if (__builtin_available(macOS 10.12, *)) {
- // Unfortunately there's no NSWindowListOrderedBackToFront,
- // so we have to manually reverse the order using an array.
- NSMutableArray<NSWindow *> *windows = [NSMutableArray<NSWindow *> new];
- [application enumerateWindowsWithOptions:NSWindowListOrderedFrontToBack
- usingBlock:^(NSWindow *window, BOOL *) {
- // For some reason AppKit will give us nil-windows, skip those
- if (!window)
- return;
-
- [windows addObject:window];
- }
- ];
-
- windowEnumerator = windows.reverseObjectEnumerator;
- } else
-#endif
- {
- // No way to get ordered list of windows, so fall back to unordered,
- // list, which typically corresponds to window creation order.
- windowEnumerator = application.windows.objectEnumerator;
- }
+ // Unfortunately there's no NSWindowListOrderedBackToFront,
+ // so we have to manually reverse the order using an array.
+ NSMutableArray<NSWindow *> *windows = [NSMutableArray<NSWindow *> new];
+ [application enumerateWindowsWithOptions:NSWindowListOrderedFrontToBack
+ usingBlock:^(NSWindow *window, BOOL *) {
+ // For some reason AppKit will give us nil-windows, skip those
+ if (!window)
+ return;
+
+ [windows addObject:window];
+ }
+ ];
+
+ windowEnumerator = windows.reverseObjectEnumerator;
for (NSWindow *window in windowEnumerator) {
// We're meddling with normal and floating windows, so leave others alone
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
index 9a5a0ab499..bec8354fcc 100644
--- a/src/plugins/platforms/ios/qiosintegration.mm
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -115,10 +115,8 @@ void QIOSIntegration::initialize()
m_touchDevice = new QTouchDevice;
m_touchDevice->setType(QTouchDevice::TouchScreen);
QTouchDevice::Capabilities touchCapabilities = QTouchDevice::Position | QTouchDevice::NormalizedPosition;
- if (__builtin_available(iOS 9, *)) {
- if (mainScreen.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable)
- touchCapabilities |= QTouchDevice::Pressure;
- }
+ if (mainScreen.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable)
+ touchCapabilities |= QTouchDevice::Pressure;
m_touchDevice->setCapabilities(touchCapabilities);
QWindowSystemInterface::registerTouchDevice(m_touchDevice);
#if QT_CONFIG(tabletevent)
diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm
index f1121a102b..4f753be21a 100644
--- a/src/plugins/platforms/ios/qiosscreen.mm
+++ b/src/plugins/platforms/ios/qiosscreen.mm
@@ -456,12 +456,7 @@ qreal QIOSScreen::devicePixelRatio() const
qreal QIOSScreen::refreshRate() const
{
-#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_NA, 100300, 110000, __WATCHOS_NA)
- if (__builtin_available(iOS 10.3, tvOS 11, *))
- return m_uiScreen.maximumFramesPerSecond;
-#endif
-
- return 60.0;
+ return m_uiScreen.maximumFramesPerSecond;
}
Qt::ScreenOrientation QIOSScreen::nativeOrientation() const
diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm
index 91a088ede1..396c769be8 100644
--- a/src/plugins/platforms/ios/qiostextresponder.mm
+++ b/src/plugins/platforms/ios/qiostextresponder.mm
@@ -244,17 +244,15 @@
self.inputAccessoryView = [[[WrapperView alloc] initWithView:accessoryView] autorelease];
#ifndef Q_OS_TVOS
- if (__builtin_available(iOS 9, *)) {
- if (platformData.value(kImePlatformDataHideShortcutsBar).toBool()) {
- // According to the docs, leadingBarButtonGroups/trailingBarButtonGroups should be set to nil to hide the shortcuts bar.
- // However, starting with iOS 10, the API has been surrounded with NS_ASSUME_NONNULL, which contradicts this and causes
- // compiler warnings. Still it is the way to go to really hide the space reserved for that.
+ if (platformData.value(kImePlatformDataHideShortcutsBar).toBool()) {
+ // According to the docs, leadingBarButtonGroups/trailingBarButtonGroups should be set to nil to hide the shortcuts bar.
+ // However, starting with iOS 10, the API has been surrounded with NS_ASSUME_NONNULL, which contradicts this and causes
+ // compiler warnings. Still it is the way to go to really hide the space reserved for that.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnonnull"
- self.inputAssistantItem.leadingBarButtonGroups = nil;
- self.inputAssistantItem.trailingBarButtonGroups = nil;
+ self.inputAssistantItem.leadingBarButtonGroups = nil;
+ self.inputAssistantItem.trailingBarButtonGroups = nil;
#pragma clang diagnostic pop
- }
}
#endif
diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm
index de60bd7c36..e64c05d099 100644
--- a/src/plugins/platforms/ios/quiview.mm
+++ b/src/plugins/platforms/ios/quiview.mm
@@ -128,21 +128,17 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
self.layer.borderWidth = 1.0;
}
-#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_NA, 110000, 110000, __WATCHOS_NA)
if (qEnvironmentVariableIsSet("QT_IOS_DEBUG_WINDOW_SAFE_AREAS")) {
- if (__builtin_available(iOS 11, tvOS 11, *)) {
- UIView *safeAreaOverlay = [[UIView alloc] initWithFrame:CGRectZero];
- [safeAreaOverlay setBackgroundColor:[UIColor colorWithRed:0.3 green:0.7 blue:0.9 alpha:0.3]];
- [self addSubview:safeAreaOverlay];
-
- safeAreaOverlay.translatesAutoresizingMaskIntoConstraints = NO;
- [safeAreaOverlay.topAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.topAnchor].active = YES;
- [safeAreaOverlay.leftAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.leftAnchor].active = YES;
- [safeAreaOverlay.rightAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.rightAnchor].active = YES;
- [safeAreaOverlay.bottomAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.bottomAnchor].active = YES;
- }
+ UIView *safeAreaOverlay = [[UIView alloc] initWithFrame:CGRectZero];
+ [safeAreaOverlay setBackgroundColor:[UIColor colorWithRed:0.3 green:0.7 blue:0.9 alpha:0.3]];
+ [self addSubview:safeAreaOverlay];
+
+ safeAreaOverlay.translatesAutoresizingMaskIntoConstraints = NO;
+ [safeAreaOverlay.topAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.topAnchor].active = YES;
+ [safeAreaOverlay.leftAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.leftAnchor].active = YES;
+ [safeAreaOverlay.rightAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.rightAnchor].active = YES;
+ [safeAreaOverlay.bottomAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.bottomAnchor].active = YES;
}
-#endif
}
return self;
@@ -355,12 +351,10 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
QTouchDevice *touchDevice = QIOSIntegration::instance()->touchDevice();
QTouchDevice::Capabilities touchCapabilities = touchDevice->capabilities();
- if (__builtin_available(iOS 9, *)) {
- if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable)
- touchCapabilities |= QTouchDevice::Pressure;
- else
- touchCapabilities &= ~QTouchDevice::Pressure;
- }
+ if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable)
+ touchCapabilities |= QTouchDevice::Pressure;
+ else
+ touchCapabilities &= ~QTouchDevice::Pressure;
touchDevice->setCapabilities(touchCapabilities);
}
@@ -668,18 +662,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
- (UIEdgeInsets)qt_safeAreaInsets
{
-#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_NA, 110000, 110000, __WATCHOS_NA)
- if (__builtin_available(iOS 11, tvOS 11, *))
- return self.safeAreaInsets;
-#endif
-
- // Fallback for iOS < 11
- UIEdgeInsets safeAreaInsets = UIEdgeInsetsZero;
- CGPoint topInset = [self convertPoint:CGPointMake(0, self.viewController.topLayoutGuide.length) fromView:nil];
- CGPoint bottomInset = [self convertPoint:CGPointMake(0, self.viewController.bottomLayoutGuide.length) fromView:nil];
- safeAreaInsets.top = topInset.y;
- safeAreaInsets.bottom = bottomInset.y;
- return safeAreaInsets;
+ return self.safeAreaInsets;
}
@end
diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro
index e61887618f..5bf2b77421 100644
--- a/src/plugins/platforms/platforms.pro
+++ b/src/plugins/platforms/platforms.pro
@@ -46,6 +46,8 @@ haiku {
SUBDIRS += haiku
}
+wasm: SUBDIRS = wasm
+
qtConfig(mirclient): SUBDIRS += mirclient
qtConfig(integrityfb): SUBDIRS += integrity
diff --git a/src/plugins/platforms/wasm/main.cpp b/src/plugins/platforms/wasm/main.cpp
new file mode 100644
index 0000000000..a4d23b4e0d
--- /dev/null
+++ b/src/plugins/platforms/wasm/main.cpp
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qpa/qplatformintegrationplugin.h>
+#include "qwasmintegration.h"
+
+QT_BEGIN_NAMESPACE
+
+class QWasmIntegrationPlugin : public QPlatformIntegrationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "wasm.json")
+public:
+ QPlatformIntegration *create(const QString &, const QStringList &) override;
+};
+
+QPlatformIntegration *QWasmIntegrationPlugin::create(const QString& system, const QStringList& paramList)
+{
+ Q_UNUSED(paramList);
+ if (!system.compare(QStringLiteral("wasm"), Qt::CaseInsensitive))
+ return new QWasmIntegration;
+
+ return nullptr;
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/platforms/wasm/qtloader.js b/src/plugins/platforms/wasm/qtloader.js
new file mode 100644
index 0000000000..37a5308034
--- /dev/null
+++ b/src/plugins/platforms/wasm/qtloader.js
@@ -0,0 +1,516 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// QtLoader provides javascript API for managing Qt application modules.
+//
+// QtLoader provides API on top of Emscripten which supports common lifecycle
+// tasks such as displaying placeholder content while the module downloads,
+// handing application exits, and checking for browser wasm support.
+//
+// There are two usage modes:
+// * Managed: QtLoader owns and manages the HTML display elements like
+// the loader and canvas.
+// * External: The embedding HTML page owns the display elements. QtLoader
+// provides event callbacks which the page reacts to.
+//
+// Managed mode usage:
+//
+// var config = {
+// containerElements : [$("container-id")];
+// }
+// var qtLoader = QtLoader(config);
+// qtLoader.loadEmscriptenModule("applicationName");
+//
+// External mode.usage:
+//
+// var config = {
+// showLoader: function() {
+// loader.style.display = 'block'
+// canvas.style.display = 'hidden'
+// },
+// showCanvas: function() {
+// loader.style.display = 'hidden'
+// canvas.style.display = 'block'
+// return canvas;
+// }
+// }
+// var qtLoader = QtLoader(config);
+// qtLoader.loadEmscriptenModule("applicationName");
+//
+// Config keys
+//
+// containerElements : [container-element, ...]
+// One or more HTML elements. QtLoader will display loader elements
+// on these while loading the applicaton, and replace the loader with a
+// canvas on load complete.
+// showLoader : function(status, containerElement)
+// Optional loading element constructor function. Implement to create
+// a custom loading screen. This function may be called multiple times,
+// while preparing the application binary. "status" is a string
+// containing the loading sub-status, and may be either "Downloading",
+// or "Compiling". The browser may be using streaming compilation, in
+// which case the wasm module is compiled during downloading and the
+// there is no separate compile step.
+// showCanvas : function(containerElement)
+// Optional canvas constructor function. Implement to create custom
+// canvas elements.
+// showExit : function(crashed, exitCode, containerElement)
+// Optional exited element constructor function.
+// showError : function(crashed, exitCode, containerElement)
+// Optional error element constructor function.
+//
+// path : <string>
+// Prefix path for wasm file, realative to the loading HMTL file.
+// restartMode : "DoNotRestart", "RestartOnExit", "RestartOnCrash"
+// Controls whether the application should be reloaded on exits. The default is "DoNotRestart"
+// restartType : "RestartModule", "ReloadPage"
+// restartLimit : <int>
+// Restart attempts limit. The default is 10.
+// stdoutEnabled : <bool>
+// stderrEnabled : <bool>
+// environment : <object>
+// key-value environment variable pairs.
+//
+// QtLoader object API
+//
+// webAssemblySupported : bool
+// webGLSupported : bool
+// canLoadQt : bool
+// Reports if WebAssembly and WebGL are supported. These are requirements for
+// running Qt applications.
+// loadEmscriptenModule(applicationName)
+// Loads the application from the given emscripten javascript module file and wasm file
+// status
+// One of "Created", "Loading", "Running", "Exited".
+// crashed
+// Set to true if there was an unclean exit.
+// exitCode
+// main()/emscripten_force_exit() return code. Valid on status change to
+// "Exited", iff crashed is false.
+// exitText
+// Abort/exit message.
+
+
+var Module = {}
+
+function QtLoader(config)
+{
+ function webAssemblySupported() {
+ return typeof WebAssembly !== "undefined"
+ }
+
+ function webGLSupported() {
+ // We expect that WebGL is supported if WebAssembly is; however
+ // the GPU may be blacklisted.
+ try {
+ var canvas = document.createElement("canvas");
+ return !!(window.WebGLRenderingContext && (canvas.getContext("webgl") || canvas.getContext("experimental-webgl")));
+ } catch (e) {
+ return false;
+ }
+ }
+
+ function canLoadQt() {
+ // The current Qt implementation requires WebAssembly (asm.js is not in use),
+ // and also WebGL (there is no raster fallback).
+ return webAssemblySupported() && webGLSupported();
+ }
+
+ function removeChildren(element) {
+ while (element.firstChild) element.removeChild(element.firstChild);
+ }
+
+ // Set default state handler functions if needed
+ if (config.containerElements !== undefined) {
+ config.showError = config.showError || function(errorText, container) {
+ removeChildren(container);
+ var errorTextElement = document.createElement("text");
+ errorTextElement.className = "QtError"
+ errorTextElement.innerHTML = errorText;
+ return errorTextElement;
+ }
+
+ config.showLoader = config.showLoader || function(loadingState, container) {
+ removeChildren(container);
+ var loadingText = document.createElement("text");
+ loadingText.className = "QtLoading"
+ loadingText.innerHTML = '<p><center> ${loadingState}...</center><p>';
+ return loadingText;
+ };
+
+ config.showCanvas = config.showCanvas || function(container) {
+ removeChildren(container);
+ var canvas = document.createElement("canvas");
+ canvas.className = "QtCanvas"
+ canvas.style = "height: 100%; width: 100%;"
+ return canvas;
+ }
+
+ config.showExit = config.showExit || function(crashed, exitCode, container) {
+ if (!crashed)
+ return undefined;
+
+ removeChildren(container);
+ var fontSize = 54;
+ var crashSymbols = ["\u{1F615}", "\u{1F614}", "\u{1F644}", "\u{1F928}", "\u{1F62C}",
+ "\u{1F915}", "\u{2639}", "\u{1F62E}", "\u{1F61E}", "\u{1F633}"];
+ var symbolIndex = Math.floor(Math.random() * crashSymbols.length);
+ var errorHtml = `<font size='${fontSize}'> ${crashSymbols[symbolIndex]} </font>`
+ var errorElement = document.createElement("text");
+ errorElement.className = "QtExit"
+ errorElement.innerHTML = errorHtml;
+ return errorElement;
+ }
+ }
+
+ config.restartMode = config.restartMode || "DoNotRestart";
+ config.restartLimit = config.restartLimit || 10;
+
+ if (config.stdoutEnabled === undefined) config.stdoutEnabled = true;
+ if (config.stderrEnabled === undefined) config.stderrEnabled = true;
+
+ // Make sure config.path is defined and ends with "/" if needed
+ if (config.path === undefined)
+ config.path = "";
+ if (config.path.length > 0 && !config.path.endsWith("/"))
+ config.path = config.path.concat("/");
+
+ if (config.environment === undefined)
+ config.environment = {};
+
+ var publicAPI = {};
+ publicAPI.webAssemblySupported = webAssemblySupported();
+ publicAPI.webGLSupported = webGLSupported();
+ publicAPI.canLoadQt = canLoadQt();
+ publicAPI.canLoadApplication = canLoadQt();
+ publicAPI.status = undefined;
+ publicAPI.loadEmscriptenModule = loadEmscriptenModule;
+
+ restartCount = 0;
+
+ function fetchResource(filePath) {
+ var fullPath = config.path + filePath;
+ return fetch(fullPath).then(function(response) {
+ if (!response.ok) {
+ self.error = response.status + " " + response.statusText + " " + response.url;
+ setStatus("Error");
+ return Promise.reject(self.error)
+ } else {
+ return response;
+ }
+ });
+ }
+
+ function fetchText(filePath) {
+ return fetchResource(filePath).then(function(response) {
+ return response.text();
+ });
+ }
+
+ function fetchThenCompileWasm(response) {
+ return response.arrayBuffer().then(function(data) {
+ self.loaderSubState = "Compiling";
+ setStatus("Loading") // trigger loaderSubState udpate
+ return WebAssembly.compile(data);
+ });
+ }
+
+ function fetchCompileWasm(filePath) {
+ return fetchResource(filePath).then(function(response) {
+ if (typeof WebAssembly.compileStreaming !== "undefined") {
+ self.loaderSubState = "Downloading/Compiling";
+ setStatus("Loading");
+ return WebAssembly.compileStreaming(response).catch(function(error) {
+ // compileStreaming may/will fail if the server does not set the correct
+ // mime type (application/wasm) for the wasm file. Fall back to fetch,
+ // then compile in this case.
+ return fetchThenCompileWasm(response);
+ });
+ } else {
+ // Fall back to fetch, then compile if compileStreaming is not supported
+ return fetchThenCompileWasm(response);
+ }
+ });
+ }
+
+ function loadEmscriptenModule(applicationName) {
+
+ // Loading in qtloader.js goes through four steps:
+ // 1) Check prerequisites
+ // 2) Download resources
+ // 3) Configure the emscripten Module object
+ // 4) Start the emcripten runtime, after which emscripten takes over
+
+ // Check for Wasm & WebGL support; set error and return before downloading resources if missing
+ if (!webAssemblySupported()) {
+ self.error = "Error: WebAssembly is not supported"
+ setStatus("Error");
+ return;
+ }
+ if (!webGLSupported()) {
+ self.error = "Error: WebGL is not supported"
+ setStatus("Error");
+ return;
+ }
+
+ // Continue waiting if loadEmscriptenModule() is called again
+ if (publicAPI.status == "Loading")
+ return;
+ self.loaderSubState = "Downloading";
+ setStatus("Loading");
+
+ // Fetch emscripten generated javascript runtime
+ var emscriptenModuleSource = undefined
+ var emscriptenModuleSourcePromise = fetchText(applicationName + ".js").then(function(source) {
+ emscriptenModuleSource = source
+ });
+
+ // Fetch and compile wasm module
+ var wasmModule = undefined;
+ var wasmModulePromise = fetchCompileWasm(applicationName + ".wasm").then(function (module) {
+ wasmModule = module;
+ });
+
+ // Wait for all resources ready
+ Promise.all([emscriptenModuleSourcePromise, wasmModulePromise]).then(function(){
+ completeLoadEmscriptenModule(applicationName, emscriptenModuleSource, wasmModule);
+ }).catch(function(error) {
+ self.error = error;
+ setStatus("Error");
+ });
+ }
+
+ function completeLoadEmscriptenModule(applicationName, emscriptenModuleSource, wasmModule) {
+
+ // The wasm binary has been compiled into a module during resource download,
+ // and is ready to be instantiated. Define the instantiateWasm callback which
+ // emscripten will call to create the instance.
+ Module.instantiateWasm = function(imports, successCallback) {
+ return WebAssembly.instantiate(wasmModule, imports).then(function(instance) {
+ successCallback(instance);
+ return instance;
+ }, function(error) {
+ self.error = error;
+ setStatus("Error");
+ });
+ };
+
+ Module.locateFile = Module.locateFile || function(filename) {
+ return config.path + filename;
+ };
+
+ // Attach status callbacks
+ Module.setStatus = Module.setStatus || function(text) {
+ // Currently the only usable status update from this function
+ // is "Running..."
+ if (text.startsWith("Running"))
+ setStatus("Running");
+ };
+ Module.monitorRunDependencies = Module.monitorRunDependencies || function(left) {
+ // console.log("monitorRunDependencies " + left)
+ };
+
+ // Attach standard out/err callbacks.
+ Module.print = Module.print || function(text) {
+ if (config.stdoutEnabled)
+ console.log(text)
+ };
+ Module.printErr = Module.printErr || function(text) {
+ // Filter out OpenGL getProcAddress warnings. Qt tries to resolve
+ // all possible function/extension names at startup which causes
+ // emscripten to spam the console log with warnings.
+ if (text.startsWith !== undefined && text.startsWith("bad name in getProcAddress:"))
+ return;
+
+ if (config.stderrEnabled)
+ console.log(text)
+ };
+
+ // Error handling: set status to "Exited", update crashed and
+ // exitCode according to exit type.
+ // Emscripten will typically call printErr with the error text
+ // as well. Note that emscripten may also throw exceptions from
+ // async callbacks. These should be handled in window.onerror by user code.
+ Module.onAbort = Module.onAbort || function(text) {
+ publicAPI.crashed = true;
+ publicAPI.exitText = text;
+ setStatus("Exited");
+ };
+ Module.quit = Module.quit || function(code, exception) {
+ if (exception.name == "ExitStatus") {
+ // Clean exit with code
+ publicAPI.exitText = undefined
+ publicAPI.exitCode = code;
+ } else {
+ publicAPI.exitText = exception.toString();
+ publicAPI.crashed = true;
+ }
+ setStatus("Exited");
+ };
+
+ // Set environment variables
+ Module.preRun = Module.preRun || []
+ Module.preRun.push(function() {
+ for (var [key, value] of Object.entries(config.environment)) {
+ Module.ENV[key.toUpperCase()] = value;
+ }
+ });
+
+ config.restart = function() {
+
+ // Restart by reloading the page. This will wipe all state which means
+ // reload loops can't be prevented.
+ if (config.restartType == "ReloadPage") {
+ location.reload();
+ }
+
+ // Restart by readling the emscripten app module.
+ ++self.restartCount;
+ if (self.restartCount > config.restartLimit) {
+ self.error = "Error: This application has crashed too many times and has been disabled. Reload the page to try again."
+ setStatus("Error");
+ return;
+ }
+ loadEmscriptenModule(applicationName);
+ };
+
+ publicAPI.exitCode = undefined;
+ publicAPI.exitText = undefined;
+ publicAPI.crashed = false;
+
+ // Finally evaluate the emscripten application script, which will
+ // reference the global Module object created above.
+ self.eval(emscriptenModuleSource); // ES5 indirect global scope eval
+ }
+
+ function setErrorContent() {
+ if (config.containerElements === undefined) {
+ if (config.showError !== undefined)
+ config.showError(self.error);
+ return;
+ }
+
+ for (container of config.containerElements) {
+ var errorElement = config.showError(self.error, container);
+ container.appendChild(errorElement);
+ }
+ }
+
+ function setLoaderContent() {
+ if (config.containerElements === undefined) {
+ if (config.showLoader !== undefined)
+ config.showLoader(self.loaderSubState);
+ return;
+ }
+
+ for (container of config.containerElements) {
+ var loaderElement = config.showLoader(self.loaderSubState, container);
+ container.appendChild(loaderElement);
+ }
+ }
+
+ function setCanvasContent() {
+ var firstCanvas;
+ if (config.containerElements === undefined) {
+ firstCanvas = config.showCanvas();
+ } else {
+ for (container of config.containerElements) {
+ var canvasElement = config.showCanvas(container);
+ container.appendChild(canvasElement);
+ }
+ firstCanvas = config.containerElements[0].firstChild;
+ }
+
+ if (Module.canvas === undefined) {
+ Module.canvas = firstCanvas;
+ }
+ }
+
+ function setExitContent() {
+
+ // publicAPI.crashed = true;
+
+ if (publicAPI.status != "Exited")
+ return;
+
+ if (config.containerElements === undefined) {
+ if (config.showExit !== undefined)
+ config.showExit(publicAPI.crashed, publicAPI.exitCode);
+ return;
+ }
+
+ if (!publicAPI.crashed)
+ return;
+
+ for (container of config.containerElements) {
+ var loaderElement = config.showExit(publicAPI.crashed, publicAPI.exitCode, container);
+ if (loaderElement !== undefined)
+ container.appendChild(loaderElement);
+ }
+ }
+
+ var committedStatus = undefined;
+ function handleStatusChange() {
+ if (publicAPI.status != "Loading" && committedStatus == publicAPI.status)
+ return;
+ committedStatus = publicAPI.status;
+
+ if (publicAPI.status == "Error") {
+ setErrorContent();
+ } else if (publicAPI.status == "Loading") {
+ setLoaderContent();
+ } else if (publicAPI.status == "Running") {
+ setCanvasContent();
+ } else if (publicAPI.status == "Exited") {
+ if (config.restartMode == "RestartOnExit" ||
+ config.restartMode == "RestartOnCrash" && publicAPI.crashed) {
+ committedStatus = undefined;
+ config.restart();
+ } else {
+ setExitContent();
+ }
+ }
+
+ // Send status change notification
+ if (config.statusChanged)
+ config.statusChanged(publicAPI.status);
+ }
+
+ function setStatus(status) {
+ if (status != "Loading" && publicAPI.status == status)
+ return;
+ publicAPI.status = status;
+
+ window.setTimeout(function() { handleStatusChange(); }, 0);
+ }
+
+ setStatus("Created");
+
+ return publicAPI;
+}
diff --git a/src/plugins/platforms/wasm/qtlogo.svg b/src/plugins/platforms/wasm/qtlogo.svg
new file mode 100644
index 0000000000..cb8989bb79
--- /dev/null
+++ b/src/plugins/platforms/wasm/qtlogo.svg
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="462pt"
+ height="339pt"
+ viewBox="0 0 462 339"
+ version="1.1"
+ id="svg2"
+ inkscape:version="0.91 r13725"
+ sodipodi:docname="TheQtCompany_logo_2.svg">
+ <metadata
+ id="metadata20">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs18" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1536"
+ inkscape:window-height="801"
+ id="namedview16"
+ showgrid="false"
+ inkscape:zoom="1.1138643"
+ inkscape:cx="270.58047"
+ inkscape:cy="174.65092"
+ inkscape:window-x="-8"
+ inkscape:window-y="-8"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg2" />
+ <path
+ fill="#41cd52"
+ d=" M 63.50 0.00 L 462.00 0.00 L 462.00 274.79 C 440.60 296.26 419.13 317.66 397.61 339.00 L 0.00 339.00 L 0.00 63.39 C 21.08 42.18 42.34 21.13 63.50 0.00 Z"
+ id="path6" />
+ <path
+ d=" M 122.37 71.33 C 137.50 61.32 156.21 58.79 174.00 58.95 C 190.94 59.16 208.72 62.13 222.76 72.24 C 232.96 79.41 239.59 90.48 244.01 101.93 C 251.16 120.73 253.26 141.03 253.50 161.01 C 253.53 181.13 252.62 201.69 245.96 220.86 C 241.50 233.90 233.01 245.48 221.81 253.52 C 229.87 266.58 238.09 279.54 246.15 292.60 C 236.02 297.27 225.92 301.97 215.78 306.62 C 207.15 292.38 198.56 278.11 189.90 263.89 C 178.19 265.81 166.21 265.66 154.44 264.36 C 140.34 262.67 125.97 258.37 115.09 248.88 C 106.73 241.64 101.48 231.51 97.89 221.21 C 92.01 203.79 90.43 185.25 90.16 166.97 C 90.02 147.21 91.28 127.14 97.24 108.18 C 101.85 93.92 109.48 79.69 122.37 71.33 Z"
+ id="path8"
+ fill="#ffffff" />
+ <path
+ d=" M 294.13 70.69 C 304.73 70.68 315.33 70.68 325.93 70.69 C 325.96 84.71 325.92 98.72 325.95 112.74 C 339.50 112.76 353.05 112.74 366.60 112.75 C 366.37 121.85 366.12 130.95 365.86 140.05 C 352.32 140.08 338.79 140.04 325.25 140.07 C 325.28 163.05 325.18 186.03 325.30 209.01 C 325.56 215.30 325.42 221.94 328.19 227.75 C 330.21 232.23 335.65 233.38 340.08 233.53 C 348.43 233.50 356.77 233.01 365.12 232.86 C 365.63 241.22 366.12 249.59 366.60 257.95 C 349.99 260.74 332.56 264.08 316.06 258.86 C 309.11 256.80 302.63 252.19 299.81 245.32 C 294.76 233.63 294.35 220.62 294.13 208.07 C 294.11 185.40 294.13 162.74 294.12 140.07 C 286.73 140.05 279.34 140.08 271.95 140.05 C 271.93 130.96 271.93 121.86 271.95 112.76 C 279.34 112.73 286.72 112.77 294.11 112.74 C 294.14 98.72 294.10 84.71 294.13 70.69 Z"
+ id="path10"
+ fill="#ffffff" />
+ <path
+ fill="#41cd52"
+ d=" M 160.51 87.70 C 170.80 86.36 181.60 86.72 191.34 90.61 C 199.23 93.73 205.93 99.84 209.47 107.58 C 214.90 119.31 216.98 132.26 218.03 145.05 C 219.17 162.07 219.01 179.25 216.66 196.17 C 215.01 206.24 212.66 216.85 205.84 224.79 C 198.92 232.76 188.25 236.18 178.01 236.98 C 167.21 237.77 155.82 236.98 146.07 231.87 C 140.38 228.84 135.55 224.09 132.73 218.27 C 129.31 211.30 127.43 203.69 126.11 196.07 C 122.13 171.91 121.17 146.91 126.61 122.89 C 128.85 113.83 132.11 104.53 138.73 97.70 C 144.49 91.85 152.51 88.83 160.51 87.70 Z"
+ id="path12" />
+</svg>
diff --git a/src/plugins/platforms/wasm/qwasmbackingstore.cpp b/src/plugins/platforms/wasm/qwasmbackingstore.cpp
new file mode 100644
index 0000000000..5b40c44807
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmbackingstore.cpp
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwasmbackingstore.h"
+#include "qwasmwindow.h"
+#include "qwasmcompositor.h"
+
+#include <QtGui/qopengltexture.h>
+#include <QtGui/qmatrix4x4.h>
+#include <QtGui/qpainter.h>
+#include <private/qguiapplication_p.h>
+#include <qpa/qplatformscreen.h>
+
+#include <QtGui/qbackingstore.h>
+
+QT_BEGIN_NAMESPACE
+
+QWasmBackingStore::QWasmBackingStore(QWasmCompositor *compositor, QWindow *window)
+ : QPlatformBackingStore(window)
+ , m_compositor(compositor)
+ , m_texture(new QOpenGLTexture(QOpenGLTexture::Target2D))
+{
+ QWasmWindow *wasmWindow = static_cast<QWasmWindow *>(window->handle());
+ if (wasmWindow)
+ wasmWindow->setBackingStore(this);
+}
+
+QWasmBackingStore::~QWasmBackingStore()
+{
+}
+
+QPaintDevice *QWasmBackingStore::paintDevice()
+{
+ return &m_image;
+}
+
+void QWasmBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
+{
+ Q_UNUSED(window);
+ Q_UNUSED(region);
+ Q_UNUSED(offset);
+
+ m_dirty |= region;
+ m_compositor->requestRedraw();
+}
+
+void QWasmBackingStore::updateTexture()
+{
+ if (m_dirty.isNull())
+ return;
+
+ if (!m_texture->isCreated()) {
+ m_texture->setMinificationFilter(QOpenGLTexture::Nearest);
+ m_texture->setMagnificationFilter(QOpenGLTexture::Nearest);
+ m_texture->setWrapMode(QOpenGLTexture::ClampToEdge);
+ m_texture->setData(m_image, QOpenGLTexture::DontGenerateMipMaps);
+ m_texture->create();
+ }
+ m_texture->bind();
+
+ QRegion fixed;
+ QRect imageRect = m_image.rect();
+
+ for (const QRect &rect : m_dirty) {
+
+ // Convert device-independent dirty region to device region
+ qreal dpr = m_image.devicePixelRatio();
+ QRect deviceRect = QRect(rect.topLeft() * dpr, rect.size() * dpr);
+
+ // intersect with image rect to be sure
+ QRect r = imageRect & deviceRect;
+ // if the rect is wide enough it is cheaper to just extend it instead of doing an image copy
+ if (r.width() >= imageRect.width() / 2) {
+ r.setX(0);
+ r.setWidth(imageRect.width());
+ }
+
+ fixed |= r;
+ }
+
+ for (const QRect &rect : fixed) {
+ // if the sub-rect is full-width we can pass the image data directly to
+ // OpenGL instead of copying, since there is no gap between scanlines
+ if (rect.width() == imageRect.width()) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
+ m_image.constScanLine(rect.y()));
+ } else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
+ m_image.copy(rect).constBits());
+ }
+ }
+ /* End of code taken from QEGLPlatformBackingStore */
+
+ m_dirty = QRegion();
+}
+
+void QWasmBackingStore::beginPaint(const QRegion &region)
+{
+ m_dirty |= region;
+ // Keep backing store device pixel ratio in sync with window
+ if (m_image.devicePixelRatio() != window()->devicePixelRatio())
+ resize(backingStore()->size(), backingStore()->staticContents());
+
+ QPainter painter(&m_image);
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+ const QColor blank = Qt::transparent;
+ for (const QRect &rect : region)
+ painter.fillRect(rect, blank);
+}
+
+void QWasmBackingStore::resize(const QSize &size, const QRegion &staticContents)
+{
+ Q_UNUSED(staticContents)
+
+ m_image = QImage(size * window()->devicePixelRatio(), QImage::Format_RGB32);
+ m_image.setDevicePixelRatio(window()->devicePixelRatio());
+
+ if (m_texture->isCreated())
+ m_texture->destroy();
+}
+
+QImage QWasmBackingStore::toImage() const
+{
+ // used by QPlatformBackingStore::composeAndFlush
+ return m_image;
+}
+
+const QImage &QWasmBackingStore::getImageRef() const
+{
+ return m_image;
+}
+
+const QOpenGLTexture *QWasmBackingStore::getUpdatedTexture()
+{
+ updateTexture();
+ return m_texture.data();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmbackingstore.h b/src/plugins/platforms/wasm/qwasmbackingstore.h
new file mode 100644
index 0000000000..6ffa262e3d
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmbackingstore.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWASMBACKINGSTORE_H
+#define QWASMBACKINGSTORE_H
+
+#include <qpa/qplatformbackingstore.h>
+#include <QtGui/qimage.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLTexture;
+class QRegion;
+class QWasmCompositor;
+
+class QWasmBackingStore : public QPlatformBackingStore
+{
+public:
+ QWasmBackingStore(QWasmCompositor *compositor, QWindow *window);
+ ~QWasmBackingStore();
+
+ QPaintDevice *paintDevice() override;
+
+ void beginPaint(const QRegion &) override;
+ void flush(QWindow *window, const QRegion &region, const QPoint &offset) override;
+ void resize(const QSize &size, const QRegion &staticContents) override;
+ QImage toImage() const override;
+ const QImage &getImageRef() const;
+
+ const QOpenGLTexture *getUpdatedTexture();
+
+protected:
+ void updateTexture();
+
+private:
+ QWasmCompositor *m_compositor;
+ QImage m_image;
+ QScopedPointer<QOpenGLTexture> m_texture;
+ QRegion m_dirty;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWASMBACKINGSTORE_H
diff --git a/src/plugins/platforms/wasm/qwasmcompositor.cpp b/src/plugins/platforms/wasm/qwasmcompositor.cpp
new file mode 100644
index 0000000000..f3ea013325
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmcompositor.cpp
@@ -0,0 +1,721 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwasmcompositor.h"
+#include "qwasmwindow.h"
+#include "qwasmstylepixmaps_p.h"
+
+#include <QtGui/qopengltexture.h>
+
+#include <QtGui/private/qwindow_p.h>
+#include <QtGui/qopenglcontext.h>
+#include <QtGui/qopenglfunctions.h>
+#include <QtGui/qopengltextureblitter.h>
+#include <QtGui/qpainter.h>
+#include <private/qpixmapcache_p.h>
+
+#include <private/qguiapplication_p.h>
+
+#include <qpa/qwindowsysteminterface.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtGui/qguiapplication.h>
+
+Q_GUI_EXPORT int qt_defaultDpiX();
+
+QWasmCompositedWindow::QWasmCompositedWindow()
+ : window(nullptr)
+ , parentWindow(nullptr)
+ , flushPending(false)
+ , visible(false)
+{
+}
+
+QWasmCompositor::QWasmCompositor()
+ : m_frameBuffer(nullptr)
+ , m_blitter(new QOpenGLTextureBlitter)
+ , m_needComposit(false)
+ , m_inFlush(false)
+ , m_inResize(false)
+ , m_isEnabled(true)
+ , m_targetDevicePixelRatio(1)
+{
+}
+
+QWasmCompositor::~QWasmCompositor()
+{
+ delete m_frameBuffer;
+}
+
+void QWasmCompositor::setEnabled(bool enabled)
+{
+ m_isEnabled = enabled;
+}
+
+void QWasmCompositor::addWindow(QWasmWindow *window, QWasmWindow *parentWindow)
+{
+ QWasmCompositedWindow compositedWindow;
+ compositedWindow.window = window;
+ compositedWindow.parentWindow = parentWindow;
+ m_compositedWindows.insert(window, compositedWindow);
+
+ if (parentWindow == 0)
+ m_windowStack.append(window);
+ else
+ m_compositedWindows[parentWindow].childWindows.append(window);
+
+ notifyTopWindowChanged(window);
+}
+
+void QWasmCompositor::removeWindow(QWasmWindow *window)
+{
+ QWasmWindow *platformWindow = m_compositedWindows[window].parentWindow;
+
+ if (platformWindow) {
+ QWasmWindow *parentWindow = window;
+ m_compositedWindows[parentWindow].childWindows.removeAll(window);
+ }
+
+ m_windowStack.removeAll(window);
+ m_compositedWindows.remove(window);
+
+ notifyTopWindowChanged(window);
+}
+
+void QWasmCompositor::setScreen(QWasmScreen *screen)
+{
+ m_screen = screen;
+}
+
+void QWasmCompositor::setVisible(QWasmWindow *window, bool visible)
+{
+ QWasmCompositedWindow &compositedWindow = m_compositedWindows[window];
+ if (compositedWindow.visible == visible)
+ return;
+
+ compositedWindow.visible = visible;
+ compositedWindow.flushPending = true;
+ if (visible)
+ compositedWindow.damage = compositedWindow.window->geometry();
+ else
+ m_globalDamage = compositedWindow.window->geometry(); // repaint previosly covered area.
+
+ requestRedraw();
+}
+
+void QWasmCompositor::raise(QWasmWindow *window)
+{
+ if (m_compositedWindows.size() <= 1)
+ return;
+
+ QWasmCompositedWindow &compositedWindow = m_compositedWindows[window];
+ compositedWindow.damage = compositedWindow.window->geometry();
+ m_windowStack.removeAll(window);
+ m_windowStack.append(window);
+
+ notifyTopWindowChanged(window);
+}
+
+void QWasmCompositor::lower(QWasmWindow *window)
+{
+ if (m_compositedWindows.size() <= 1)
+ return;
+
+ m_windowStack.removeAll(window);
+ m_windowStack.prepend(window);
+ QWasmCompositedWindow &compositedWindow = m_compositedWindows[window];
+ m_globalDamage = compositedWindow.window->geometry(); // repaint previosly covered area.
+
+ notifyTopWindowChanged(window);
+}
+
+void QWasmCompositor::setParent(QWasmWindow *window, QWasmWindow *parent)
+{
+ m_compositedWindows[window].parentWindow = parent;
+
+ requestRedraw();
+}
+
+void QWasmCompositor::flush(QWasmWindow *window, const QRegion &region)
+{
+ QWasmCompositedWindow &compositedWindow = m_compositedWindows[window];
+ compositedWindow.flushPending = true;
+ compositedWindow.damage = region;
+
+ requestRedraw();
+}
+
+int QWasmCompositor::windowCount() const
+{
+ return m_windowStack.count();
+}
+
+
+void QWasmCompositor::redrawWindowContent()
+{
+ // Redraw window content by sending expose events. This redraw
+ // will cause a backing store flush, which will call requestRedraw()
+ // to composit.
+ for (QWasmWindow *platformWindow : m_windowStack) {
+ QWindow *window = platformWindow->window();
+ QWindowSystemInterface::handleExposeEvent<QWindowSystemInterface::SynchronousDelivery>(
+ window, QRect(QPoint(0, 0), window->geometry().size()));
+ }
+}
+
+void QWasmCompositor::requestRedraw()
+{
+ if (m_needComposit)
+ return;
+
+ m_needComposit = true;
+ QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
+}
+
+QWindow *QWasmCompositor::windowAt(QPoint p, int padding) const
+{
+ int index = m_windowStack.count() - 1;
+ // qDebug() << "window at" << "point" << p << "window count" << index;
+
+ while (index >= 0) {
+ const QWasmCompositedWindow &compositedWindow = m_compositedWindows[m_windowStack.at(index)];
+ //qDebug() << "windwAt testing" << compositedWindow.window <<
+
+ QRect geometry = compositedWindow.window->windowFrameGeometry()
+ .adjusted(-padding, -padding, padding, padding);
+
+ if (compositedWindow.visible && geometry.contains(p))
+ return m_windowStack.at(index)->window();
+ --index;
+ }
+
+ return 0;
+}
+
+QWindow *QWasmCompositor::keyWindow() const
+{
+ return m_windowStack.at(m_windowStack.count() - 1)->window();
+}
+
+bool QWasmCompositor::event(QEvent *ev)
+{
+ if (ev->type() == QEvent::UpdateRequest) {
+ if (m_isEnabled)
+ frame();
+ return true;
+ }
+
+ return QObject::event(ev);
+}
+
+void QWasmCompositor::blit(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, const QOpenGLTexture *texture, QRect targetGeometry)
+{
+ QMatrix4x4 m;
+ m.translate(-1.0f, -1.0f);
+
+ m.scale(2.0f / (float)screen->geometry().width(),
+ 2.0f / (float)screen->geometry().height());
+
+ m.translate((float)targetGeometry.width() / 2.0f,
+ (float)-targetGeometry.height() / 2.0f);
+
+ m.translate(targetGeometry.x(), screen->geometry().height() - targetGeometry.y());
+
+ m.scale(0.5f * (float)targetGeometry.width(),
+ 0.5f * (float)targetGeometry.height());
+
+ blitter->blit(texture->textureId(), m, QOpenGLTextureBlitter::OriginTopLeft);
+}
+
+void QWasmCompositor::drawWindowContent(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window)
+{
+ QWasmBackingStore *backingStore = window->backingStore();
+
+ QOpenGLTexture const *texture = backingStore->getUpdatedTexture();
+
+ blit(blitter, screen, texture, window->geometry());
+}
+
+QPalette QWasmCompositor::makeWindowPalette()
+{
+ QPalette palette;
+ palette.setColor(QPalette::Active, QPalette::Highlight,
+ palette.color(QPalette::Active, QPalette::Highlight));
+ palette.setColor(QPalette::Active, QPalette::Base,
+ palette.color(QPalette::Active, QPalette::Highlight));
+ palette.setColor(QPalette::Inactive, QPalette::Highlight,
+ palette.color(QPalette::Inactive, QPalette::Dark));
+ palette.setColor(QPalette::Inactive, QPalette::Base,
+ palette.color(QPalette::Inactive, QPalette::Dark));
+ palette.setColor(QPalette::Inactive, QPalette::HighlightedText,
+ palette.color(QPalette::Inactive, QPalette::Window));
+
+ return palette;
+}
+
+QRect QWasmCompositor::titlebarRect(QWasmTitleBarOptions tb, QWasmCompositor::SubControls subcontrol)
+{
+ QRect ret;
+ const int controlMargin = 2;
+ const int controlHeight = tb.rect.height() - controlMargin *2;
+ const int delta = controlHeight + controlMargin;
+ int offset = 0;
+
+ bool isMinimized = tb.state & Qt::WindowMinimized;
+ bool isMaximized = tb.state & Qt::WindowMaximized;
+
+ ret = tb.rect;
+ switch (subcontrol) {
+ case SC_TitleBarLabel:
+ if (tb.flags & Qt::WindowSystemMenuHint)
+ ret.adjust(delta, 0, -delta, 0);
+ break;
+ case SC_TitleBarCloseButton:
+ if (tb.flags & Qt::WindowSystemMenuHint) {
+ ret.adjust(0, 0, -delta, 0);
+ offset += delta;
+ }
+ break;
+ case SC_TitleBarMaxButton:
+ if (!isMaximized && tb.flags & Qt::WindowMaximizeButtonHint) {
+ ret.adjust(0, 0, -delta*2, 0);
+ offset += (delta +delta);
+ }
+ break;
+ case SC_TitleBarNormalButton:
+ if (isMinimized && (tb.flags & Qt::WindowMinimizeButtonHint))
+ offset += delta;
+ else if (isMaximized && (tb.flags & Qt::WindowMaximizeButtonHint))
+ ret.adjust(0, 0, -delta*2, 0);
+ offset += (delta +delta);
+ break;
+ case SC_TitleBarSysMenu:
+ if (tb.flags & Qt::WindowSystemMenuHint) {
+ ret.setRect(tb.rect.left() + controlMargin, tb.rect.top() + controlMargin,
+ controlHeight, controlHeight);
+ }
+ break;
+ default:
+ break;
+ };
+
+ if (subcontrol != SC_TitleBarLabel && subcontrol != SC_TitleBarSysMenu) {
+ ret.setRect(tb.rect.right() - offset, tb.rect.top() + controlMargin,
+ controlHeight, controlHeight);
+ }
+
+ if (qApp->layoutDirection() == Qt::LeftToRight)
+ return ret;
+
+ QRect rect = ret;
+ rect.translate(2 * (tb.rect.right() - ret.right()) +
+ ret.width() - tb.rect.width(), 0);
+
+ return rect;
+}
+
+int dpiScaled(qreal value)
+{
+ return value * (qreal(qt_defaultDpiX()) / 96.0);
+}
+
+QWasmCompositor::QWasmTitleBarOptions QWasmCompositor::makeTitleBarOptions(const QWasmWindow *window)
+{
+ int width = window->windowFrameGeometry().width();
+ int border = window->borderWidth();
+
+ QWasmTitleBarOptions titleBarOptions;
+
+ titleBarOptions.rect = QRect(border, border, width - 2 * border, window->titleHeight());
+ titleBarOptions.flags = window->window()->flags();
+ titleBarOptions.state = window->window()->windowState();
+
+ bool isMaximized = titleBarOptions.state & Qt::WindowMaximized; // this gets reset when maximized
+
+ if (titleBarOptions.flags & (Qt::WindowTitleHint))
+ titleBarOptions.subControls |= SC_TitleBarLabel;
+ if (titleBarOptions.flags & Qt::WindowMaximizeButtonHint) {
+ if (isMaximized)
+ titleBarOptions.subControls |= SC_TitleBarNormalButton;
+ else
+ titleBarOptions.subControls |= SC_TitleBarMaxButton;
+ }
+ if (titleBarOptions.flags & Qt::WindowSystemMenuHint) {
+ titleBarOptions.subControls |= SC_TitleBarCloseButton;
+ titleBarOptions.subControls |= SC_TitleBarSysMenu;
+ }
+
+
+ titleBarOptions.palette = QWasmCompositor::makeWindowPalette();
+
+ if (window->window()->isActive())
+ titleBarOptions.palette.setCurrentColorGroup(QPalette::Active);
+ else
+ titleBarOptions.palette.setCurrentColorGroup(QPalette::Inactive);
+
+ if (window->activeSubControl() != QWasmCompositor::SC_None)
+ titleBarOptions.subControls = window->activeSubControl();
+
+ if (!window->window()->title().isEmpty())
+ titleBarOptions.titleBarOptionsString = window->window()->title();
+
+ return titleBarOptions;
+}
+
+void QWasmCompositor::drawWindowDecorations(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window)
+{
+ int width = window->windowFrameGeometry().width();
+ int height = window->windowFrameGeometry().height();
+ qreal dpr = window->devicePixelRatio();
+
+ QImage image(QSize(width * dpr, height * dpr), QImage::Format_RGB32);
+ image.setDevicePixelRatio(dpr);
+ QPainter painter(&image);
+ painter.fillRect(QRect(0, 0, width, height), painter.background());
+
+ QWasmTitleBarOptions titleBarOptions = makeTitleBarOptions(window);
+
+ drawTitlebarWindow(titleBarOptions, &painter);
+
+ QWasmFrameOptions frameOptions;
+ frameOptions.rect = QRect(0, 0, width, height);
+ frameOptions.lineWidth = dpiScaled(4.);
+
+ drawFrameWindow(frameOptions, &painter);
+
+ painter.end();
+
+ QOpenGLTexture texture(QOpenGLTexture::Target2D);
+ texture.setMinificationFilter(QOpenGLTexture::Nearest);
+ texture.setMagnificationFilter(QOpenGLTexture::Nearest);
+ texture.setWrapMode(QOpenGLTexture::ClampToEdge);
+ texture.setData(image, QOpenGLTexture::DontGenerateMipMaps);
+ texture.create();
+ texture.bind();
+
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image.width(), image.height(), GL_RGBA, GL_UNSIGNED_BYTE,
+ image.constScanLine(0));
+
+ blit(blitter, screen, &texture, QRect(window->windowFrameGeometry().topLeft(), QSize(width, height)));
+}
+
+void QWasmCompositor::drawFrameWindow(QWasmFrameOptions options, QPainter *painter)
+{
+ int x = options.rect.x();
+ int y = options.rect.y();
+ int w = options.rect.width();
+ int h = options.rect.height();
+ const QColor &c1 = options.palette.light().color();
+ const QColor &c2 = options.palette.shadow().color();
+ const QColor &c3 = options.palette.midlight().color();
+ const QColor &c4 = options.palette.dark().color();
+ const QBrush *fill = 0;
+
+ const qreal devicePixelRatio = painter->device()->devicePixelRatioF();
+ if (!qFuzzyCompare(devicePixelRatio, qreal(1))) {
+ const qreal inverseScale = qreal(1) / devicePixelRatio;
+ painter->scale(inverseScale, inverseScale);
+ x = qRound(devicePixelRatio * x);
+ y = qRound(devicePixelRatio * y);
+ w = qRound(devicePixelRatio * w);
+ h = qRound(devicePixelRatio * h);
+ }
+
+ QPen oldPen = painter->pen();
+ QPoint a[3] = { QPoint(x, y+h-2), QPoint(x, y), QPoint(x+w-2, y) };
+ painter->setPen(c1);
+ painter->drawPolyline(a, 3);
+ QPoint b[3] = { QPoint(x, y+h-1), QPoint(x+w-1, y+h-1), QPoint(x+w-1, y) };
+ painter->setPen(c2);
+ painter->drawPolyline(b, 3);
+ if (w > 4 && h > 4) {
+ QPoint c[3] = { QPoint(x+1, y+h-3), QPoint(x+1, y+1), QPoint(x+w-3, y+1) };
+ painter->setPen(c3);
+ painter->drawPolyline(c, 3);
+ QPoint d[3] = { QPoint(x+1, y+h-2), QPoint(x+w-2, y+h-2), QPoint(x+w-2, y+1) };
+ painter->setPen(c4);
+ painter->drawPolyline(d, 3);
+ if (fill)
+ painter->fillRect(QRect(x+2, y+2, w-4, h-4), *fill);
+ }
+ painter->setPen(oldPen);
+}
+
+//from commonstyle.cpp
+static QPixmap cachedPixmapFromXPM(const char * const *xpm)
+{
+ QPixmap result;
+ const QString tag = QString::asprintf("xpm:0x%p", static_cast<const void*>(xpm));
+ if (!QPixmapCache::find(tag, &result)) {
+ result = QPixmap(xpm);
+ QPixmapCache::insert(tag, result);
+ }
+ return result;
+}
+
+void QWasmCompositor::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment,
+ const QPixmap &pixmap) const
+{
+ qreal scale = pixmap.devicePixelRatio();
+ QSize size = pixmap.size() / scale;
+ int x = rect.x();
+ int y = rect.y();
+ int w = size.width();
+ int h = size.height();
+ if ((alignment & Qt::AlignVCenter) == Qt::AlignVCenter)
+ y += rect.size().height()/2 - h/2;
+ else if ((alignment & Qt::AlignBottom) == Qt::AlignBottom)
+ y += rect.size().height() - h;
+ if ((alignment & Qt::AlignRight) == Qt::AlignRight)
+ x += rect.size().width() - w;
+ else if ((alignment & Qt::AlignHCenter) == Qt::AlignHCenter)
+ x += rect.size().width()/2 - w/2;
+
+ QRect aligned = QRect(x, y, w, h);
+ QRect inter = aligned.intersected(rect);
+
+ painter->drawPixmap(inter.x(), inter.y(), pixmap, inter.x() - aligned.x(), inter.y() - aligned.y(), inter.width() * scale, inter.height() *scale);
+}
+
+
+void QWasmCompositor::drawTitlebarWindow(QWasmTitleBarOptions tb, QPainter *painter)
+{
+ QRect ir;
+ if (tb.subControls.testFlag(SC_TitleBarLabel)) {
+ QColor left = tb.palette.highlight().color();
+ QColor right = tb.palette.base().color();
+
+ QBrush fillBrush(left);
+ if (left != right) {
+ QPoint p1(tb.rect.x(), tb.rect.top() + tb.rect.height()/2);
+ QPoint p2(tb.rect.right(), tb.rect.top() + tb.rect.height()/2);
+ QLinearGradient lg(p1, p2);
+ lg.setColorAt(0, left);
+ lg.setColorAt(1, right);
+ fillBrush = lg;
+ }
+
+ painter->fillRect(tb.rect, fillBrush);
+ ir = titlebarRect(tb, SC_TitleBarLabel);
+ painter->setPen(tb.palette.highlightedText().color());
+ painter->drawText(ir.x() + 2, ir.y(), ir.width() - 2, ir.height(),
+ Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, tb.titleBarOptionsString);
+ } // SC_TitleBarLabel
+
+ bool down = false;
+ QPixmap pixmap;
+
+ if (tb.subControls.testFlag(SC_TitleBarCloseButton)
+ && tb.flags & Qt::WindowSystemMenuHint) {
+ ir = titlebarRect(tb, SC_TitleBarCloseButton);
+ down = tb.subControls & SC_TitleBarCloseButton && (tb.state & State_Sunken);
+ pixmap = cachedPixmapFromXPM(qt_close_xpm).scaled(QSize(10, 10));
+ drawItemPixmap(painter, ir, Qt::AlignCenter, pixmap);
+ } //SC_TitleBarCloseButton
+
+ if (tb.subControls.testFlag(SC_TitleBarMaxButton)
+ && tb.flags & Qt::WindowMaximizeButtonHint
+ && !(tb.state & Qt::WindowMaximized)) {
+ ir = titlebarRect(tb, SC_TitleBarMaxButton);
+ down = tb.subControls & SC_TitleBarMaxButton && (tb.state & State_Sunken);
+ pixmap = cachedPixmapFromXPM(qt_maximize_xpm).scaled(QSize(10, 10));
+ drawItemPixmap(painter, ir, Qt::AlignCenter, pixmap);
+ } //SC_TitleBarMaxButton
+
+ bool drawNormalButton = (tb.subControls & SC_TitleBarNormalButton)
+ && (((tb.flags & Qt::WindowMinimizeButtonHint)
+ && (tb.flags & Qt::WindowMinimized))
+ || ((tb.flags & Qt::WindowMaximizeButtonHint)
+ && (tb.flags & Qt::WindowMaximized)));
+
+ if (drawNormalButton) {
+ ir = titlebarRect(tb, SC_TitleBarNormalButton);
+ down = tb.subControls & SC_TitleBarNormalButton && (tb.state & State_Sunken);
+ pixmap = cachedPixmapFromXPM(qt_normalizeup_xpm).scaled( QSize(10, 10));
+
+ drawItemPixmap(painter, ir, Qt::AlignCenter, pixmap);
+ } // SC_TitleBarNormalButton
+
+ if (tb.subControls & SC_TitleBarSysMenu && tb.flags & Qt::WindowSystemMenuHint) {
+ ir = titlebarRect(tb, SC_TitleBarSysMenu);
+ pixmap = cachedPixmapFromXPM(qt_menu_xpm).scaled(QSize(10, 10));
+ drawItemPixmap(painter, ir, Qt::AlignCenter, pixmap);
+ }
+}
+
+void QWasmCompositor::drawShadePanel(QWasmTitleBarOptions options, QPainter *painter)
+{
+ int lineWidth = 1;
+ QPalette palette = options.palette;
+ const QBrush *fill = &options.palette.brush(QPalette::Button);
+
+ int x = options.rect.x();
+ int y = options.rect.y();
+ int w = options.rect.width();
+ int h = options.rect.height();
+
+ const qreal devicePixelRatio = painter->device()->devicePixelRatioF();
+ if (!qFuzzyCompare(devicePixelRatio, qreal(1))) {
+ const qreal inverseScale = qreal(1) / devicePixelRatio;
+ painter->scale(inverseScale, inverseScale);
+
+ x = qRound(devicePixelRatio * x);
+ y = qRound(devicePixelRatio * y);
+ w = qRound(devicePixelRatio * w);
+ h = qRound(devicePixelRatio * h);
+ lineWidth = qRound(devicePixelRatio * lineWidth);
+ }
+
+ QColor shade = palette.dark().color();
+ QColor light = palette.light().color();
+
+ if (fill) {
+ if (fill->color() == shade)
+ shade = palette.shadow().color();
+ if (fill->color() == light)
+ light = palette.midlight().color();
+ }
+ QPen oldPen = painter->pen();
+ QVector<QLineF> lines;
+ lines.reserve(2*lineWidth);
+
+ painter->setPen(light);
+ int x1, y1, x2, y2;
+ int i;
+ x1 = x;
+ y1 = y2 = y;
+ x2 = x + w - 2;
+ for (i = 0; i < lineWidth; i++) // top shadow
+ lines << QLineF(x1, y1++, x2--, y2++);
+
+ x2 = x1;
+ y1 = y + h - 2;
+ for (i = 0; i < lineWidth; i++) // left shado
+ lines << QLineF(x1++, y1, x2++, y2--);
+
+ painter->drawLines(lines);
+ lines.clear();
+ painter->setPen(shade);
+ x1 = x;
+ y1 = y2 = y+h-1;
+ x2 = x+w-1;
+ for (i=0; i<lineWidth; i++) { // bottom shadow
+ lines << QLineF(x1++, y1--, x2, y2--);
+ }
+ x1 = x2;
+ y1 = y;
+ y2 = y + h - lineWidth - 1;
+ for (i = 0; i < lineWidth; i++) // right shadow
+ lines << QLineF(x1--, y1++, x2--, y2);
+
+ painter->drawLines(lines);
+ if (fill) // fill with fill color
+ painter->fillRect(x+lineWidth, y+lineWidth, w-lineWidth*2, h-lineWidth*2, *fill);
+ painter->setPen(oldPen); // restore pen
+
+}
+
+void QWasmCompositor::drawWindow(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window)
+{
+ if (window->window()->type() != Qt::Popup)
+ drawWindowDecorations(blitter, screen, window);
+ drawWindowContent(blitter, screen, window);
+}
+
+void QWasmCompositor::frame()
+{
+ if (!m_needComposit)
+ return;
+
+ m_needComposit = false;
+
+ if (m_windowStack.empty() || !m_screen)
+ return;
+
+ QWasmWindow *someWindow = nullptr;
+
+ foreach (QWasmWindow *window, m_windowStack) {
+ if (window->window()->surfaceClass() == QSurface::Window
+ && qt_window_private(static_cast<QWindow *>(window->window()))->receivedExpose) {
+ someWindow = window;
+ break;
+ }
+ }
+
+ if (!someWindow)
+ return;
+
+ if (m_context.isNull()) {
+ m_context.reset(new QOpenGLContext());
+ //mContext->setFormat(mScreen->format());
+ m_context->setScreen(m_screen->screen());
+ m_context->create();
+ }
+
+ m_context->makeCurrent(someWindow->window());
+
+ if (!m_blitter->isCreated())
+ m_blitter->create();
+
+ qreal dpr = m_screen->devicePixelRatio();
+ glViewport(0, 0, m_screen->geometry().width() * dpr, m_screen->geometry().height() * dpr);
+
+ m_context->functions()->glClearColor(0.2, 0.2, 0.2, 1.0);
+ m_context->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+
+ m_blitter->bind();
+ m_blitter->setRedBlueSwizzle(true);
+
+ foreach (QWasmWindow *window, m_windowStack) {
+ QWasmCompositedWindow &compositedWindow = m_compositedWindows[window];
+
+ if (!compositedWindow.visible)
+ continue;
+
+ drawWindow(m_blitter.data(), m_screen, window);
+ }
+
+ m_blitter->release();
+
+ if (someWindow && someWindow->window()->surfaceType() == QSurface::OpenGLSurface)
+ m_context->swapBuffers(someWindow->window());
+}
+
+void QWasmCompositor::notifyTopWindowChanged(QWasmWindow *window)
+{
+ QWindow *modalWindow;
+ bool blocked = QGuiApplicationPrivate::instance()->isWindowBlocked(window->window(), &modalWindow);
+
+ if (blocked) {
+ raise(static_cast<QWasmWindow*>(modalWindow->handle()));
+ return;
+ }
+
+ requestRedraw();
+ QWindowSystemInterface::handleWindowActivated(window->window());
+}
diff --git a/src/plugins/platforms/wasm/qwasmcompositor.h b/src/plugins/platforms/wasm/qwasmcompositor.h
new file mode 100644
index 0000000000..4e5ed46cec
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmcompositor.h
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWASMCOMPOSITOR_H
+#define QWASMCOMPOSITOR_H
+
+#include <QtGui/qregion.h>
+#include <qpa/qplatformwindow.h>
+
+#include <QtGui/qopengltextureblitter.h>
+#include <QtGui/qopengltexture.h>
+#include <QtGui/qpalette.h>
+#include <QtGui/qpainter.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWasmWindow;
+class QWasmScreen;
+class QOpenGLContext;
+class QOpenGLTextureBlitter;
+
+class QWasmCompositedWindow
+{
+public:
+ QWasmCompositedWindow();
+
+ QWasmWindow *window;
+ QWasmWindow *parentWindow;
+ QRegion damage;
+ bool flushPending;
+ bool visible;
+ QList<QWasmWindow *> childWindows;
+};
+
+class QWasmCompositor : public QObject
+{
+ Q_OBJECT
+public:
+ QWasmCompositor();
+ ~QWasmCompositor();
+
+ enum QWasmSubControl {
+ SC_None = 0x00000000,
+ SC_TitleBarSysMenu = 0x00000001,
+ SC_TitleBarMinButton = 0x00000002,
+ SC_TitleBarMaxButton = 0x00000004,
+ SC_TitleBarCloseButton = 0x00000008,
+ SC_TitleBarNormalButton = 0x00000010,
+ SC_TitleBarLabel = 0x00000100
+ };
+ Q_DECLARE_FLAGS(SubControls, QWasmSubControl)
+
+ enum QWasmStateFlag {
+ State_None = 0x00000000,
+ State_Enabled = 0x00000001,
+ State_Raised = 0x00000002,
+ State_Sunken = 0x00000004
+ };
+ Q_DECLARE_FLAGS(StateFlags, QWasmStateFlag)
+
+ struct QWasmTitleBarOptions {
+ QRect rect;
+ Qt::WindowFlags flags;
+ int state;
+ QPalette palette;
+ QString titleBarOptionsString;
+ QWasmCompositor::SubControls subControls;
+ };
+
+ struct QWasmFrameOptions {
+ QRect rect;
+ int lineWidth;
+ QPalette palette;
+ };
+
+ void setEnabled(bool enabled);
+
+ void addWindow(QWasmWindow *window, QWasmWindow *parentWindow = nullptr);
+ void removeWindow(QWasmWindow *window);
+ void setScreen(QWasmScreen *screen);
+
+ void setVisible(QWasmWindow *window, bool visible);
+ void raise(QWasmWindow *window);
+ void lower(QWasmWindow *window);
+ void setParent(QWasmWindow *window, QWasmWindow *parent);
+
+ void flush(QWasmWindow *surface, const QRegion &region);
+
+ int windowCount() const;
+
+ void redrawWindowContent();
+ void requestRedraw();
+
+ QWindow *windowAt(QPoint p, int padding = 0) const;
+ QWindow *keyWindow() const;
+
+ bool event(QEvent *event);
+
+ static QWasmTitleBarOptions makeTitleBarOptions(const QWasmWindow *window);
+ static QRect titlebarRect(QWasmTitleBarOptions tb, QWasmCompositor::SubControls subcontrol);
+
+private slots:
+ void frame();
+
+private:
+ void createFrameBuffer();
+ void flushCompletedCallback(int32_t);
+ void notifyTopWindowChanged(QWasmWindow *window);
+ void drawWindow(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window);
+ void drawWindowContent(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window);
+ void blit(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, const QOpenGLTexture *texture, QRect targetGeometry);
+
+ void drawWindowDecorations(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window);
+ void drwPanelButton();
+
+ QImage *m_frameBuffer;
+ QScopedPointer<QOpenGLContext> m_context;
+ QScopedPointer<QOpenGLTextureBlitter> m_blitter;
+ QWasmScreen *m_screen;
+
+ QHash<QWasmWindow *, QWasmCompositedWindow> m_compositedWindows;
+ QList<QWasmWindow *> m_windowStack;
+ QRegion m_globalDamage; // damage caused by expose, window close, etc.
+ bool m_needComposit;
+ bool m_inFlush;
+ bool m_inResize;
+ bool m_isEnabled;
+ QSize m_targetSize;
+ qreal m_targetDevicePixelRatio;
+
+ static QPalette makeWindowPalette();
+
+ void drawFrameWindow(QWasmFrameOptions options, QPainter *painter);
+ void drawTitlebarWindow(QWasmTitleBarOptions options, QPainter *painter);
+ void drawShadePanel(QWasmTitleBarOptions options, QPainter *painter);
+ void drawItemPixmap(QPainter *painter, const QRect &rect,
+ int alignment, const QPixmap &pixmap) const;
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QWasmCompositor::SubControls)
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/wasm/qwasmcursor.cpp b/src/plugins/platforms/wasm/qwasmcursor.cpp
new file mode 100644
index 0000000000..54804a55b3
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmcursor.cpp
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwasmcursor.h"
+
+#include <QtCore/qdebug.h>
+
+#include <emscripten/emscripten.h>
+
+void QWasmCursor::changeCursor(QCursor *windowCursor, QWindow *window)
+{
+ if (windowCursor == nullptr)
+ return;
+
+ // FIXME: The HTML5 plugin sets the cursor on the native canvas; when using multiple windows
+ // multiple cursors need to be managed taking mouse postion and stacking into account.
+ Q_UNUSED(window);
+
+ // Bitmap and custom cursors are not implemented (will fall back to "auto")
+ if (windowCursor->shape() == Qt::BitmapCursor || windowCursor->shape() >= Qt::CustomCursor)
+ qWarning() << "QWasmCursor: bitmap and custom cursors are not supported";
+
+ QByteArray htmlCursorName = cursorShapeToHtml(windowCursor->shape());
+
+ if (htmlCursorName.isEmpty())
+ htmlCursorName = "auto";
+
+ // Set cursor on the main canvas
+ EM_ASM_ARGS({
+ if (Module['canvas']) {
+ Module['canvas'].style['cursor'] = Pointer_stringify($0);
+ }
+ }, htmlCursorName.constData());
+}
+
+QByteArray QWasmCursor::cursorShapeToHtml(Qt::CursorShape shape)
+{
+ QByteArray cursorName;
+
+ switch (shape) {
+ case Qt::ArrowCursor:
+ cursorName = "default";
+ break;
+ case Qt::UpArrowCursor:
+ break;
+ case Qt::CrossCursor:
+ cursorName = "crosshair";
+ break;
+ case Qt::WaitCursor:
+ cursorName = "wait";
+ break;
+ case Qt::IBeamCursor:
+ cursorName = "text";
+ break;
+ case Qt::SizeVerCursor:
+ cursorName = "ns-resize";
+ break;
+ case Qt::SizeHorCursor:
+ cursorName = "ew-resize";
+ break;
+ case Qt::SizeBDiagCursor:
+ cursorName = "nesw-resize";
+ break;
+ case Qt::SizeFDiagCursor:
+ cursorName = "nwse-resize";
+ break;
+ case Qt::SizeAllCursor:
+ break; // no equivalent?
+ case Qt::BlankCursor:
+ cursorName = "none";
+ break;
+ case Qt::SplitVCursor:
+ cursorName = "row-resize";
+ break;
+ case Qt::SplitHCursor:
+ cursorName = "col-resize";
+ break;
+ case Qt::PointingHandCursor:
+ cursorName = "pointer";
+ break;
+ case Qt::ForbiddenCursor:
+ cursorName = "not-allowed";
+ break;
+ case Qt::WhatsThisCursor:
+ cursorName = "help";
+ break;
+ case Qt::BusyCursor:
+ cursorName = "wait";
+ break;
+ case Qt::OpenHandCursor:
+ break; // no equivalent?
+ case Qt::ClosedHandCursor:
+ break; // no equivalent?
+ case Qt::DragCopyCursor:
+ break; // no equivalent?
+ case Qt::DragMoveCursor:
+ break; // no equivalent?
+ case Qt::DragLinkCursor:
+ break; // no equivalent?
+ default:
+ break;
+ }
+
+ return cursorName;
+}
diff --git a/src/plugins/platforms/wasm/qwasmcursor.h b/src/plugins/platforms/wasm/qwasmcursor.h
new file mode 100644
index 0000000000..516e07aa31
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmcursor.h
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWASMCURSOR_H
+#define QWASMCURSOR_H
+
+#include <qpa/qplatformcursor.h>
+
+class QWasmCursor : public QPlatformCursor
+{
+public:
+ void changeCursor(QCursor *windowCursor, QWindow *window) override;
+
+ QByteArray cursorShapeToHtml(Qt::CursorShape shape);
+};
+
+#endif
diff --git a/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp
new file mode 100644
index 0000000000..41355d72ae
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwasmeventdispatcher.h"
+
+#include <QtCore/qcoreapplication.h>
+
+#include <emscripten.h>
+
+class QWasmEventDispatcherPrivate : public QEventDispatcherUNIXPrivate
+{
+
+};
+
+QWasmEventDispatcher *g_htmlEventDispatcher;
+
+QWasmEventDispatcher::QWasmEventDispatcher(QObject *parent)
+ : QUnixEventDispatcherQPA(parent)
+{
+
+ g_htmlEventDispatcher = this;
+}
+
+QWasmEventDispatcher::~QWasmEventDispatcher()
+{
+ g_htmlEventDispatcher = nullptr;
+}
+
+bool QWasmEventDispatcher::registerRequestUpdateCallback(std::function<void(void)> callback)
+{
+ if (!g_htmlEventDispatcher || !g_htmlEventDispatcher->m_hasMainLoop)
+ return false;
+
+ g_htmlEventDispatcher->m_requestUpdateCallbacks.append(callback);
+ emscripten_resume_main_loop();
+ return true;
+}
+
+void QWasmEventDispatcher::maintainTimers()
+{
+ if (!g_htmlEventDispatcher || !g_htmlEventDispatcher->m_hasMainLoop)
+ return;
+
+ g_htmlEventDispatcher->doMaintainTimers();
+}
+
+bool QWasmEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
+{
+ // WaitForMoreEvents is not supported (except for in combination with EventLoopExec below),
+ // and we don't want the unix event dispatcher base class to attempt to wait either.
+ flags &= ~QEventLoop::WaitForMoreEvents;
+
+ // Handle normal processEvents.
+ if (!(flags & QEventLoop::EventLoopExec))
+ return QUnixEventDispatcherQPA::processEvents(flags);
+
+ // Handle processEvents from QEventLoop::exec():
+ //
+ // At this point the application has created its root objects on
+ // the stack and has called app.exec() which has called into this
+ // function via QEventLoop.
+ //
+ // The application now expects that exec() will not return until
+ // app exit time. However, the browser expects that we return
+ // control to it periodically, also after initial setup in main().
+
+ // EventLoopExec for nested event loops is not supported.
+ Q_ASSERT(!m_hasMainLoop);
+ m_hasMainLoop = true;
+
+ // Call emscripten_set_main_loop_arg() with a callback which processes
+ // events. Also set simulateInfiniteLoop to true which makes emscripten
+ // return control to the browser without unwinding the C++ stack.
+ auto callback = [](void *eventDispatcher) {
+ QWasmEventDispatcher *that = static_cast<QWasmEventDispatcher *>(eventDispatcher);
+
+ // Save and clear updateRequest callbacks so we can register new ones
+ auto requestUpdateCallbacksCopy = that->m_requestUpdateCallbacks;
+ that->m_requestUpdateCallbacks.clear();
+
+ // Repaint all windows
+ for (auto callback : qAsConst(requestUpdateCallbacksCopy))
+ callback();
+
+ // Pause main loop if no updates were requested. Updates will be
+ // restarted again by registerRequestUpdateCallback().
+ if (that->m_requestUpdateCallbacks.isEmpty())
+ emscripten_pause_main_loop();
+
+ that->doMaintainTimers();
+ };
+ int fps = 0; // update using requestAnimationFrame
+ int simulateInfiniteLoop = 1;
+ emscripten_set_main_loop_arg(callback, this, fps, simulateInfiniteLoop);
+
+ // Note: the above call never returns, not even at app exit
+ return false;
+}
+
+void QWasmEventDispatcher::doMaintainTimers()
+{
+ Q_D(QWasmEventDispatcher);
+
+ // This functon schedules native timers in order to wake up to
+ // process events and activate Qt timers. This is done using the
+ // emscripten_async_call() API which schedules a new timer.
+ // There is unfortunately no way to cancel or update a current
+ // native timer.
+
+ // Schedule a zero-timer to continue processing any pending events.
+ if (!m_hasZeroTimer && hasPendingEvents()) {
+ auto callback = [](void *eventDispatcher) {
+ QWasmEventDispatcher *that = static_cast<QWasmEventDispatcher *>(eventDispatcher);
+ that->m_hasZeroTimer = false;
+ that->QUnixEventDispatcherQPA::processEvents(QEventLoop::AllEvents);
+
+ // Processing events may have posted new events or created new timers
+ that->doMaintainTimers();
+ };
+
+ emscripten_async_call(callback, this, 0);
+ m_hasZeroTimer = true;
+ return;
+ }
+
+ auto timespecToNanosec = [](timespec ts) -> uint64_t { return ts.tv_sec * 1000 + ts.tv_nsec / (1000 * 1000); };
+
+ // Get current time and time-to-first-Qt-timer. This polls for system
+ // time, and we use this time as the current time for the duration of this call.
+ timespec toWait;
+ bool hasTimers = d->timerList.timerWait(toWait);
+ if (!hasTimers)
+ return; // no timer needed
+
+ uint64_t currentTime = timespecToNanosec(d->timerList.currentTime);
+ uint64_t toWaitDuration = timespecToNanosec(toWait);
+
+ // The currently scheduled timer target is stored in m_currentTargetTime.
+ // We can re-use it if the new target is equivalent or later.
+ uint64_t newTargetTime = currentTime + toWaitDuration;
+ if (newTargetTime >= m_currentTargetTime)
+ return; // existing timer is good
+
+ // Schedule a native timer with a callback which processes events (and timers)
+ auto callback = [](void *eventDispatcher) {
+ QWasmEventDispatcher *that = static_cast<QWasmEventDispatcher *>(eventDispatcher);
+ that->m_currentTargetTime = std::numeric_limits<uint64_t>::max();
+ that->QUnixEventDispatcherQPA::processEvents(QEventLoop::AllEvents);
+
+ // Processing events may have posted new events or created new timers
+ that->doMaintainTimers();
+ };
+ emscripten_async_call(callback, this, toWaitDuration);
+ m_currentTargetTime = newTargetTime;
+}
diff --git a/src/plugins/platforms/wasm/qwasmeventdispatcher.h b/src/plugins/platforms/wasm/qwasmeventdispatcher.h
new file mode 100644
index 0000000000..5300b3de73
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmeventdispatcher.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWASMEVENTDISPATCHER_H
+#define QWASMEVENTDISPATCHER_H
+
+#include <QtCore/qhash.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtEventDispatcherSupport/private/qunixeventdispatcher_qpa_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWasmEventDispatcherPrivate;
+
+class QWasmEventDispatcher : public QUnixEventDispatcherQPA
+{
+ Q_DECLARE_PRIVATE(QWasmEventDispatcher)
+public:
+ explicit QWasmEventDispatcher(QObject *parent = nullptr);
+ ~QWasmEventDispatcher();
+
+ static bool registerRequestUpdateCallback(std::function<void(void)> callback);
+ static void maintainTimers();
+
+protected:
+ bool processEvents(QEventLoop::ProcessEventsFlags flags) override;
+ void doMaintainTimers();
+
+private:
+ bool m_hasMainLoop = false;
+ bool m_hasZeroTimer = false;
+ uint64_t m_currentTargetTime = std::numeric_limits<uint64_t>::max();
+ QVector<std::function<void(void)>> m_requestUpdateCallbacks;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp
new file mode 100644
index 0000000000..6545eda4e3
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp
@@ -0,0 +1,522 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwasmeventtranslator.h"
+#include "qwasmeventdispatcher.h"
+#include "qwasmcompositor.h"
+#include "qwasmintegration.h"
+
+#include <QtGui/qevent.h>
+#include <qpa/qwindowsysteminterface.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qobject.h>
+
+#include <QtCore/qdeadlinetimer.h>
+
+#include <iostream>
+
+QT_BEGIN_NAMESPACE
+
+// macOS CTRL <-> META switching. We most likely want to enable
+// the existing switching code in QtGui, but for now do it here.
+static bool g_usePlatformMacCtrlMetaSwitching = false;
+
+QWasmEventTranslator::QWasmEventTranslator(QObject *parent)
+ : QObject(parent)
+ , draggedWindow(nullptr)
+ , pressedButtons(Qt::NoButton)
+ , resizeMode(QWasmWindow::ResizeNone)
+{
+ emscripten_set_keydown_callback(0, (void *)this, 1, &keyboard_cb);
+ emscripten_set_keyup_callback(0, (void *)this, 1, &keyboard_cb);
+
+ emscripten_set_mousedown_callback(0, (void *)this, 1, &mouse_cb);
+ emscripten_set_mouseup_callback(0, (void *)this, 1, &mouse_cb);
+ emscripten_set_mousemove_callback(0, (void *)this, 1, &mouse_cb);
+
+ emscripten_set_focus_callback(0, (void *)this, 1, &focus_cb);
+
+ emscripten_set_wheel_callback(0, (void *)this, 1, &wheel_cb);
+
+ touchDevice = new QTouchDevice;
+ touchDevice->setType(QTouchDevice::TouchScreen);
+ touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::NormalizedPosition);
+ QWindowSystemInterface::registerTouchDevice(touchDevice);
+
+ emscripten_set_touchstart_callback("#canvas", (void *)this, 1, &touchCallback);
+ emscripten_set_touchend_callback("#canvas", (void *)this, 1, &touchCallback);
+ emscripten_set_touchmove_callback("#canvas", (void *)this, 1, &touchCallback);
+ emscripten_set_touchcancel_callback("#canvas", (void *)this, 1, &touchCallback);
+
+ // The Platform Detect: expand coverage and move as needed
+ enum Platform {
+ GenericPlatform,
+ MacOSPlatform
+ };
+ Platform platform =
+ Platform(EM_ASM_INT("if (navigator.platform.includes(\"Mac\")) return 1; return 0;"));
+
+ g_usePlatformMacCtrlMetaSwitching = (platform == MacOSPlatform);
+}
+
+template <typename Event>
+QFlags<Qt::KeyboardModifier> QWasmEventTranslator::translatKeyModifier(const Event *event)
+{
+ QFlags<Qt::KeyboardModifier> keyModifier = Qt::NoModifier;
+ if (event->shiftKey)
+ keyModifier |= Qt::ShiftModifier;
+ if (event->ctrlKey) {
+ if (g_usePlatformMacCtrlMetaSwitching)
+ keyModifier |= Qt::MetaModifier;
+ else
+ keyModifier |= Qt::ControlModifier;
+ }
+ if (event->altKey)
+ keyModifier |= Qt::AltModifier;
+ if (event->metaKey) {
+ if (g_usePlatformMacCtrlMetaSwitching)
+ keyModifier |= Qt::ControlModifier;
+ else
+ keyModifier |= Qt::MetaModifier;
+ }
+ return keyModifier;
+}
+
+QFlags<Qt::KeyboardModifier> QWasmEventTranslator::translateKeyboardEventModifier(const EmscriptenKeyboardEvent *keyEvent)
+{
+ QFlags<Qt::KeyboardModifier> keyModifier = translatKeyModifier(keyEvent);
+ if (keyEvent->location == DOM_KEY_LOCATION_NUMPAD) {
+ keyModifier |= Qt::KeypadModifier;
+ }
+
+ return keyModifier;
+}
+
+QFlags<Qt::KeyboardModifier> QWasmEventTranslator::translateMouseEventModifier(const EmscriptenMouseEvent *mouseEvent)
+{
+ return translatKeyModifier(mouseEvent);
+}
+
+int QWasmEventTranslator::keyboard_cb(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
+{
+ Q_UNUSED(userData)
+
+ bool alphanumeric;
+ Qt::Key qtKey = translateEmscriptKey(keyEvent, &alphanumeric);
+
+ QEvent::Type keyType = QEvent::None;
+ switch (eventType) {
+ case EMSCRIPTEN_EVENT_KEYPRESS:
+ case EMSCRIPTEN_EVENT_KEYDOWN: //down
+ keyType = QEvent::KeyPress;
+ break;
+ case EMSCRIPTEN_EVENT_KEYUP: //up
+ keyType = QEvent::KeyRelease;
+ break;
+ default:
+ break;
+ };
+
+ if (keyType == QEvent::None)
+ return 0;
+
+ QString keyText = alphanumeric ? QString(keyEvent->key) : QString();
+ bool accepted = QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(
+ 0, keyType, qtKey, translateKeyboardEventModifier(keyEvent), keyText);
+ QWasmEventDispatcher::maintainTimers();
+ return accepted ? 1 : 0;
+}
+
+Qt::Key QWasmEventTranslator::translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey, bool *outAlphanumeric)
+{
+ Qt::Key qtKey;
+ if (outAlphanumeric)
+ *outAlphanumeric = false;
+
+ switch (emscriptKey->keyCode) {
+ case KeyMultiply: qtKey = Qt::Key_Asterisk; *outAlphanumeric = true; break;
+ case KeyAdd: qtKey = Qt::Key_Plus; *outAlphanumeric = true; break;
+ case KeyMinus: qtKey = Qt::Key_Minus; *outAlphanumeric = true; break;
+ case KeySubtract: qtKey = Qt::Key_Minus; *outAlphanumeric = true; break;
+ case KeyDecimal: qtKey = Qt::Key_Period; *outAlphanumeric = true; break;
+ case KeyDivide: qtKey = Qt::Key_Slash; *outAlphanumeric = true; break;
+ case KeyNumPad0: qtKey = Qt::Key_0; *outAlphanumeric = true; break;
+ case KeyNumPad1: qtKey = Qt::Key_1; *outAlphanumeric = true; break;
+ case KeyNumPad2: qtKey = Qt::Key_2; *outAlphanumeric = true; break;
+ case KeyNumPad3: qtKey = Qt::Key_3; *outAlphanumeric = true; break;
+ case KeyNumPad4: qtKey = Qt::Key_4; *outAlphanumeric = true; break;
+ case KeyNumPad5: qtKey = Qt::Key_5; *outAlphanumeric = true; break;
+ case KeyNumPad6: qtKey = Qt::Key_6; *outAlphanumeric = true; break;
+ case KeyNumPad7: qtKey = Qt::Key_7; *outAlphanumeric = true; break;
+ case KeyNumPad8: qtKey = Qt::Key_8; *outAlphanumeric = true; break;
+ case KeyNumPad9: qtKey = Qt::Key_9; *outAlphanumeric = true; break;
+ case KeyComma: qtKey = Qt::Key_Comma; *outAlphanumeric = true; break;
+ case KeyPeriod: qtKey = Qt::Key_Period; *outAlphanumeric = true; break;
+ case KeySlash: qtKey = Qt::Key_Slash; *outAlphanumeric = true; break;
+ case KeySemiColon: qtKey = Qt::Key_Semicolon; *outAlphanumeric = true; break;
+ case KeyEquals: qtKey = Qt::Key_Equal; *outAlphanumeric = true; break;
+ case KeyOpenBracket: qtKey = Qt::Key_BracketLeft; *outAlphanumeric = true; break;
+ case KeyCloseBracket: qtKey = Qt::Key_BracketRight; *outAlphanumeric = true; break;
+ case KeyBackSlash: qtKey = Qt::Key_Backslash; *outAlphanumeric = true; break;
+ case KeyMeta:
+ Q_FALLTHROUGH();
+ case KeyMetaRight:
+ qtKey = Qt::Key_Meta;
+ break;
+ case KeyTab: qtKey = Qt::Key_Tab; break;
+ case KeyClear: qtKey = Qt::Key_Clear; break;
+ case KeyBackSpace: qtKey = Qt::Key_Backspace; break;
+ case KeyEnter: qtKey = Qt::Key_Return; break;
+ case KeyShift: qtKey = Qt::Key_Shift; break;
+ case KeyControl: qtKey = Qt::Key_Control; break;
+ case KeyAlt: qtKey = Qt::Key_Alt; break;
+ case KeyCapsLock: qtKey = Qt::Key_CapsLock; break;
+ case KeyEscape: qtKey = Qt::Key_Escape; break;
+ case KeyPageUp: qtKey = Qt::Key_PageUp; break;
+ case KeyPageDown: qtKey = Qt::Key_PageDown; break;
+ case KeyEnd: qtKey = Qt::Key_End; break;
+ case KeyHome: qtKey = Qt::Key_Home; break;
+ case KeyLeft: qtKey = Qt::Key_Left; break;
+ case KeyUp: qtKey = Qt::Key_Up; break;
+ case KeyRight: qtKey = Qt::Key_Right; break;
+ case KeyDown: qtKey = Qt::Key_Down; break;
+ case KeyBrightnessDown: qtKey = Qt::Key_MonBrightnessDown; break;
+ case KeyBrightnessUp: qtKey = Qt::Key_MonBrightnessUp; break;
+ case KeyMediaTrackPrevious: qtKey = Qt::Key_MediaPrevious; break;
+ case KeyMediaPlayPause: qtKey = Qt::Key_MediaTogglePlayPause; break;
+ case KeyMediaTrackNext: qtKey = Qt::Key_MediaNext; break;
+ case KeyAudioVolumeMute: qtKey = Qt::Key_VolumeMute; break;
+ case KeyAudioVolumeDown: qtKey = Qt::Key_VolumeDown; break;
+ case KeyAudioVolumeUp: qtKey = Qt::Key_VolumeUp; break;
+ case KeyDelete: qtKey = Qt::Key_Delete; break;
+
+ case KeyF1: qtKey = Qt::Key_F1; break;
+ case KeyF2: qtKey = Qt::Key_F2; break;
+ case KeyF3: qtKey = Qt::Key_F3; break;
+ case KeyF4: qtKey = Qt::Key_F4; break;
+ case KeyF5: qtKey = Qt::Key_F5; break;
+ case KeyF6: qtKey = Qt::Key_F6; break;
+ case KeyF7: qtKey = Qt::Key_F7; break;
+ case KeyF8: qtKey = Qt::Key_F8; break;
+ case KeyF9: qtKey = Qt::Key_F9; break;
+ case KeyF10: qtKey = Qt::Key_F10; break;
+ case KeyF11: qtKey = Qt::Key_F11; break;
+ case KeyF12: qtKey = Qt::Key_F12; break;
+ case 124: qtKey = Qt::Key_F13; break;
+ case 125: qtKey = Qt::Key_F14; break;
+
+ case KeySpace:
+ default:
+ if (outAlphanumeric)
+ *outAlphanumeric = true;
+ qtKey = static_cast<Qt::Key>(emscriptKey->keyCode);
+ break;
+ }
+
+ // Handle Mac command key. Using event->keyCode as above is
+ // no reliable since the codes differ between browsers.
+ if (qstrncmp(emscriptKey->key, "Meta", 4) == 0) {
+ qtKey = Qt::Key_Meta;
+ *outAlphanumeric = false;
+ }
+
+ if (g_usePlatformMacCtrlMetaSwitching) {
+ if (qtKey == Qt::Key_Meta)
+ qtKey = Qt::Key_Control;
+ else if (qtKey == Qt::Key_Control)
+ qtKey = Qt::Key_Meta;
+ }
+
+ return qtKey;
+}
+
+Qt::MouseButton QWasmEventTranslator::translateMouseButton(unsigned short button)
+{
+ if (button == 0)
+ return Qt::LeftButton;
+ else if (button == 1)
+ return Qt::MiddleButton;
+ else if (button == 2)
+ return Qt::RightButton;
+
+ return Qt::NoButton;
+}
+
+int QWasmEventTranslator::mouse_cb(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
+{
+ QWasmEventTranslator *translator = (QWasmEventTranslator*)userData;
+ translator->processMouse(eventType,mouseEvent);
+ QWasmEventDispatcher::maintainTimers();
+ return 0;
+}
+
+void resizeWindow(QWindow *window, QWasmWindow::ResizeMode mode,
+ QRect startRect, QPoint amount)
+{
+ if (mode == QWasmWindow::ResizeNone)
+ return;
+
+ bool top = mode == QWasmWindow::ResizeTopLeft ||
+ mode == QWasmWindow::ResizeTop ||
+ mode == QWasmWindow::ResizeTopRight;
+
+ bool bottom = mode == QWasmWindow::ResizeBottomLeft ||
+ mode == QWasmWindow::ResizeBottom ||
+ mode == QWasmWindow::ResizeBottomRight;
+
+ bool left = mode == QWasmWindow::ResizeLeft ||
+ mode == QWasmWindow::ResizeTopLeft ||
+ mode == QWasmWindow::ResizeBottomLeft;
+
+ bool right = mode == QWasmWindow::ResizeRight ||
+ mode == QWasmWindow::ResizeTopRight ||
+ mode == QWasmWindow::ResizeBottomRight;
+
+ int x1 = startRect.left();
+ int y1 = startRect.top();
+ int x2 = startRect.right();
+ int y2 = startRect.bottom();
+
+ if (left)
+ x1 += amount.x();
+ if (top)
+ y1 += amount.y();
+ if (right)
+ x2 += amount.x();
+ if (bottom)
+ y2 += amount.y();
+
+ int w = x2-x1;
+ int h = y2-y1;
+
+ if (w < window->minimumWidth()) {
+ if (left)
+ x1 -= window->minimumWidth() - w;
+
+ w = window->minimumWidth();
+ }
+
+ if (h < window->minimumHeight()) {
+ if (top)
+ y1 -= window->minimumHeight() - h;
+
+ h = window->minimumHeight();
+ }
+
+ window->setGeometry(x1, y1, w, h);
+}
+
+void QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent)
+{
+ auto timestamp = mouseEvent->timestamp;
+ QPoint point(mouseEvent->canvasX, mouseEvent->canvasY);
+
+ QEvent::Type buttonEventType = QEvent::None;
+
+ Qt::MouseButton button = translateMouseButton(mouseEvent->button);
+ Qt::KeyboardModifiers modifiers = translateMouseEventModifier(mouseEvent);
+
+ QWindow *window2 = QWasmIntegration::get()->compositor()->windowAt(point, 5);
+ QWasmWindow *htmlWindow = static_cast<QWasmWindow*>(window2->handle());
+ bool onFrame = false;
+ if (window2 && !window2->geometry().contains(point))
+ onFrame = true;
+
+ QPoint localPoint(point.x() - window2->geometry().x(), point.y() - window2->geometry().y());
+
+ switch (eventType) {
+ case 5: //down
+ {
+ if (window2)
+ window2->raise();
+
+ pressedButtons.setFlag(button);
+
+ if (mouseEvent->button == 0) {
+ pressedWindow = window2;
+ buttonEventType = QEvent::MouseButtonPress;
+ if (htmlWindow && window2->flags().testFlag(Qt::WindowTitleHint) && htmlWindow->isPointOnTitle(point))
+ draggedWindow = window2;
+ else if (htmlWindow && htmlWindow->isPointOnResizeRegion(point)) {
+ draggedWindow = window2;
+ resizeMode = htmlWindow->resizeModeAtPoint(point);
+ resizePoint = point;
+ resizeStartRect = window2->geometry();
+ }
+ }
+
+ htmlWindow->injectMousePressed(localPoint, point, button, modifiers);
+ break;
+ }
+ case 6: //up
+ {
+ pressedButtons.setFlag(translateMouseButton(mouseEvent->button), false);
+ buttonEventType = QEvent::MouseButtonRelease;
+ QWasmWindow *oldWindow = nullptr;
+
+ if (mouseEvent->button == 0 && pressedWindow) {
+ oldWindow = static_cast<QWasmWindow*>(pressedWindow->handle());
+ pressedWindow = nullptr;
+ }
+
+
+ if (mouseEvent->button == 0) {
+ draggedWindow = nullptr;
+ resizeMode = QWasmWindow::ResizeNone;
+ }
+
+ if (oldWindow)
+ oldWindow->injectMouseReleased(localPoint, point, button, modifiers);
+ break;
+ }
+ case 8://move //drag event
+ {
+ buttonEventType = QEvent::MouseMove;
+ if (resizeMode == QWasmWindow::ResizeNone && draggedWindow) {
+ draggedWindow->setX(draggedWindow->x() + mouseEvent->movementX);
+ draggedWindow->setY(draggedWindow->y() + mouseEvent->movementY);
+ }
+
+ if (resizeMode != QWasmWindow::ResizeNone) {
+ QPoint delta = QPoint(mouseEvent->canvasX, mouseEvent->canvasY) - resizePoint;
+ resizeWindow(draggedWindow, resizeMode, resizeStartRect, delta);
+ }
+ break;
+ }
+ default:
+ break;
+ };
+
+ if (window2 && !onFrame) {
+ QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>(
+ window2, timestamp, localPoint, point, pressedButtons, button, buttonEventType, modifiers);
+ }
+}
+
+int QWasmEventTranslator::focus_cb(int /*eventType*/, const EmscriptenFocusEvent */*focusEvent*/, void */*userData*/)
+{
+ return 0;
+}
+
+int QWasmEventTranslator::wheel_cb(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData)
+{
+ Q_UNUSED(eventType)
+ Q_UNUSED(userData)
+
+ EmscriptenMouseEvent mouseEvent = wheelEvent->mouse;
+
+ int scrollFactor = 0;
+ switch (wheelEvent->deltaMode) {
+ case DOM_DELTA_PIXEL://chrome safari
+ scrollFactor = 1;
+ break;
+ case DOM_DELTA_LINE: //firefox
+ scrollFactor = 12;
+ break;
+ case DOM_DELTA_PAGE:
+ scrollFactor = 20;
+ break;
+ };
+
+ Qt::KeyboardModifiers modifiers = translateMouseEventModifier(&mouseEvent);
+ auto timestamp = mouseEvent.timestamp;
+ QPoint globalPoint(mouseEvent.canvasX, mouseEvent.canvasY);
+
+ QWindow *window2 = QWasmIntegration::get()->compositor()->windowAt(globalPoint, 5);
+
+ QPoint localPoint(globalPoint.x() - window2->geometry().x(), globalPoint.y() - window2->geometry().y());
+
+ QPoint pixelDelta;
+
+ if (wheelEvent->deltaY != 0) pixelDelta.setY(wheelEvent->deltaY * scrollFactor);
+ if (wheelEvent->deltaX != 0) pixelDelta.setX(wheelEvent->deltaX * scrollFactor);
+
+ QWindowSystemInterface::handleWheelEvent(window2, timestamp, localPoint, globalPoint, QPoint(), pixelDelta, modifiers);
+ return 1;
+}
+
+int QWasmEventTranslator::touchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
+{
+ QList<QWindowSystemInterface::TouchPoint> touchPointList;
+ touchPointList.reserve(touchEvent->numTouches);
+ QWindow *window2;
+
+ for (int i = 0; i < touchEvent->numTouches; i++) {
+
+ const EmscriptenTouchPoint *touches = &touchEvent->touches[i];
+
+ QPoint point(touches->canvasX, touches->canvasY);
+ window2 = QWasmIntegration::get()->compositor()->windowAt(point, 5);
+
+ QWindowSystemInterface::TouchPoint touchPoint;
+
+ auto cX = point.x();
+ auto cY = point.y();
+ touchPoint.area = QRect(0, 0, 8, 8);
+ touchPoint.area.moveCenter(QPointF(cX,cY)); // simulate area
+
+ touchPoint.id = touches->identifier;
+ touchPoint.normalPosition = QPointF(cX / window2->width(), cY / window2->height());
+
+ switch (eventType) {
+ case EMSCRIPTEN_EVENT_TOUCHSTART:
+ touchPoint.state = Qt::TouchPointPressed;
+ break;
+ case EMSCRIPTEN_EVENT_TOUCHEND:
+ touchPoint.state = Qt::TouchPointReleased;
+ break;
+ case EMSCRIPTEN_EVENT_TOUCHMOVE:
+ touchPoint.state = Qt::TouchPointMoved;
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+
+ touchPointList.append(touchPoint);
+ }
+
+ QWasmEventTranslator *wasmEventTranslator = (QWasmEventTranslator*)userData;
+ QFlags<Qt::KeyboardModifier> keyModifier = translatKeyModifier(touchEvent);
+
+ if (eventType != EMSCRIPTEN_EVENT_TOUCHCANCEL)
+ QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(window2, wasmEventTranslator->getTimestamp(), wasmEventTranslator->touchDevice, touchPointList, keyModifier);
+ else
+ QWindowSystemInterface::handleTouchCancelEvent(window2, wasmEventTranslator->getTimestamp(), wasmEventTranslator->touchDevice, keyModifier);
+
+ QCoreApplication::processEvents();
+ return 1;
+}
+
+quint64 QWasmEventTranslator::getTimestamp()
+{
+ return QDeadlineTimer::current().deadlineNSecs() / 1000;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.h b/src/plugins/platforms/wasm/qwasmeventtranslator.h
new file mode 100644
index 0000000000..11430a57a2
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmeventtranslator.h
@@ -0,0 +1,210 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWASMEVENTTRANSLATOR_H
+#define QWASMEVENTTRANSLATOR_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qpoint.h>
+#include <emscripten/html5.h>
+#include "qwasmwindow.h"
+#include <QtGui/qtouchdevice.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWindow;
+
+class QWasmEventTranslator : public QObject
+{
+ Q_OBJECT
+
+ enum KeyCode {
+ // numpad
+ KeyNumPad0 = 0x60,
+ KeyNumPad1 = 0x61,
+ KeyNumPad2 = 0x62,
+ KeyNumPad3 = 0x63,
+ KeyNumPad4 = 0x64,
+ KeyNumPad5 = 0x65,
+ KeyNumPad6 = 0x66,
+ KeyNumPad7 = 0x67,
+ KeyNumPad8 = 0x68,
+ KeyNumPad9 = 0x69,
+ KeyMultiply = 0x6A,
+ KeyAdd = 0x6B,
+ KeySeparator = 0x6C,
+ KeySubtract = 0x6D,
+ KeyDecimal = 0x6E,
+ KeyDivide = 0x6F,
+ KeyMeta = 0x5B,
+ KeyMetaRight = 0x5C,
+ ////////
+ KeyClear = 0x90,
+ KeyEnter = 0xD,
+ KeyBackSpace = 0x08,
+ KeyCancel = 0x03,
+ KeyTab = 0x09,
+ KeyShift = 0x10,
+ KeyControl = 0x11,
+ KeyAlt = 0x12,
+ KeyPause = 0x13,
+ KeyCapsLock = 0x14,
+ KeyEscape = 0x1B,
+ KeySpace = 0x20,
+ KeyPageUp = 0x21,
+ KeyPageDown = 0x22,
+ KeyEnd = 0x23,
+ KeyHome = 0x24,
+ KeyLeft = 0x25,
+ KeyUp = 0x26,
+ KeyRight = 0x27,
+ KeyDown = 0x28,
+ KeyComma = 0xBC,
+ KeyPeriod = 0xBE,
+ KeySlash = 0xBF,
+ KeyZero = 0x30,
+ KeyOne = 0x31,
+ KeyTwo = 0x32,
+ KeyThree = 0x33,
+ KeyFour = 0x34,
+ KeyFive = 0x35,
+ KeySix = 0x36,
+ KeySeven = 0x37,
+ KeyEight = 0x38,
+ KeyNine = 0x39,
+ KeyBrightnessDown = 0xD8,
+ KeyBrightnessUp = 0xD9,
+ KeyMediaTrackPrevious = 0xB1,
+ KeyMediaPlayPause = 0xB3,
+ KeyMediaTrackNext = 0xB0,
+ KeyAudioVolumeMute = 0xAD,
+ KeyAudioVolumeDown = 0xAE,
+ KeyAudioVolumeUp = 0xAF,
+ KeySemiColon = 0xBA,
+ KeyEquals = 0xBB,
+ KeyMinus = 0xBD,
+ KeyA = 0x41,
+ KeyB = 0x42,
+ KeyC = 0x43,
+ KeyD = 0x44,
+ KeyE = 0x45,
+ KeyF = 0x46,
+ KeyG = 0x47,
+ KeyH = 0x48,
+ KeyI = 0x49,
+ KeyJ = 0x4A,
+ KeyK = 0x4B,
+ KeyL = 0x4C,
+ KeyM = 0x4D,
+ KeyN = 0x4E,
+ KeyO = 0x4F,
+ KeyP = 0x50,
+ KeyQ = 0x51,
+ KeyR = 0x52,
+ KeyS = 0x53,
+ KeyT = 0x54,
+ KeyU = 0x55,
+ KeyV = 0x56,
+ KeyW = 0x57,
+ KeyX = 0x58,
+ KeyY = 0x59,
+ KeyZ = 0x5A,
+ KeyOpenBracket = 0xDB,
+ KeyBackSlash = 0xDC,
+ KeyCloseBracket = 0xDD,
+ KeyF1 = 0x70,
+ KeyF2 = 0x71,
+ KeyF3 = 0x72,
+ KeyF4 = 0x73,
+ KeyF5 = 0x74,
+ KeyF6 = 0x75,
+ KeyF7 = 0x76,
+ KeyF8 = 0x77,
+ KeyF9 = 0x78,
+ KeyF10 = 0x79,
+ KeyF11 = 0x7A,
+ KeyF12 = 0x7B,
+ KeyDelete = 0x2E,
+ KeyNumLock = 0x90,
+ KeyScrollLock = 0x91,
+ KeyPrintScreen = 0x9A,
+ KeyInsert = 0x9B,
+ KeyHelp = 0x9C,
+ KeyBackQuote = 0xC0,
+ KeyQuote = 0xDE,
+ KeyFinal = 0x18,
+ KeyConvert = 0x1C,
+ KeyNonConvert = 0x1D,
+ KeyAccept = 0x1E,
+ KeyModeChange = 0x1F,
+ KeyKana = 0x15,
+ KeyKanji = 0x19,
+ KeyUndefined = 0x0
+ };
+
+public:
+
+ explicit QWasmEventTranslator(QObject *parent = 0);
+
+ static int keyboard_cb(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData);
+ static int mouse_cb(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
+ static int focus_cb(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData);
+ static int wheel_cb(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData);
+
+ static int touchCallback(int eventType, const EmscriptenTouchEvent *ev, void *userData);
+
+ void processEvents();
+
+Q_SIGNALS:
+ void getWindowAt(const QPoint &point, QWindow **window);
+private:
+ static Qt::Key translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey, bool *outAlphanumretic);
+ template <typename Event>
+ static QFlags<Qt::KeyboardModifier> translatKeyModifier(const Event *event);
+ static QFlags<Qt::KeyboardModifier> translateKeyboardEventModifier(const EmscriptenKeyboardEvent *keyEvent);
+ static QFlags<Qt::KeyboardModifier> translateMouseEventModifier(const EmscriptenMouseEvent *mouseEvent);
+ static Qt::MouseButton translateMouseButton(unsigned short button);
+
+ void processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent);
+
+private:
+ QWindow *draggedWindow;
+ QWindow *pressedWindow;
+ Qt::MouseButtons pressedButtons;
+
+ QWasmWindow::ResizeMode resizeMode;
+ QPoint resizePoint;
+ QRect resizeStartRect;
+ QTouchDevice *touchDevice;
+ quint64 getTimestamp();
+};
+
+QT_END_NAMESPACE
+#endif // QWASMEVENTTRANSLATOR_H
diff --git a/src/plugins/platforms/wasm/qwasmfontdatabase.cpp b/src/plugins/platforms/wasm/qwasmfontdatabase.cpp
new file mode 100644
index 0000000000..0c72dfddc4
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmfontdatabase.cpp
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwasmfontdatabase.h"
+
+#include <QtCore/qfile.h>
+
+QT_BEGIN_NAMESPACE
+
+void QWasmFontDatabase::populateFontDatabase()
+{
+ // Load font file from resources. Currently
+ // all fonts needs to be bundled with the nexe
+ // as Qt resources.
+ QStringList fontFileNames = QStringList() << QStringLiteral(":/fonts/Vera.ttf")
+ << QStringLiteral(":/fonts/DejaVuSans.ttf");
+
+ foreach (const QString &fontFileName, fontFileNames) {
+ QFile theFont(fontFileName);
+ if (!theFont.open(QIODevice::ReadOnly))
+ break;
+
+ QFreeTypeFontDatabase::addTTFile(theFont.readAll(), fontFileName.toLatin1());
+ }
+}
+
+QFontEngine *QWasmFontDatabase::fontEngine(const QFontDef &fontDef, void *handle)
+{
+ return QFreeTypeFontDatabase::fontEngine(fontDef, handle);
+}
+
+QStringList QWasmFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style,
+ QFont::StyleHint styleHint,
+ QChar::Script script) const
+{
+ QStringList fallbacks
+ = QFreeTypeFontDatabase::fallbacksForFamily(family, style, styleHint, script);
+
+ // Add the vera.ttf font (loaded in populateFontDatabase above) as a falback font
+ // to all other fonts (except itself).
+ const QString veraFontFamily = QStringLiteral("Bitstream Vera Sans");
+ if (family != veraFontFamily)
+ fallbacks.append(veraFontFamily);
+
+ return fallbacks;
+}
+
+QStringList QWasmFontDatabase::addApplicationFont(const QByteArray &fontData,
+ const QString &fileName)
+{
+ return QFreeTypeFontDatabase::addApplicationFont(fontData, fileName);
+}
+
+void QWasmFontDatabase::releaseHandle(void *handle)
+{
+ QFreeTypeFontDatabase::releaseHandle(handle);
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmfontdatabase.h b/src/plugins/platforms/wasm/qwasmfontdatabase.h
new file mode 100644
index 0000000000..891f12859e
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmfontdatabase.h
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWASMFONTDATABASE_H
+#define QWASMFONTDATABASE_H
+
+#include <QtFontDatabaseSupport/private/qfreetypefontdatabase_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWasmFontDatabase : public QFreeTypeFontDatabase
+{
+public:
+ void populateFontDatabase() override;
+ QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override;
+ QStringList fallbacksForFamily(const QString &family, QFont::Style style,
+ QFont::StyleHint styleHint,
+ QChar::Script script) const override;
+ QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName) override;
+ void releaseHandle(void *handle) override;
+};
+QT_END_NAMESPACE
+#endif
diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp
new file mode 100644
index 0000000000..1be909f0a0
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmintegration.cpp
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwasmintegration.h"
+#include "qwasmeventtranslator.h"
+#include "qwasmeventdispatcher.h"
+#include "qwasmcompositor.h"
+#include "qwasmopenglcontext.h"
+#include "qwasmtheme.h"
+
+#include "qwasmwindow.h"
+#ifndef QT_NO_OPENGL
+# include "qwasmbackingstore.h"
+#endif
+#include "qwasmfontdatabase.h"
+#if defined(Q_OS_UNIX)
+#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
+#endif
+#include <qpa/qplatformwindow.h>
+#include <QtGui/qscreen.h>
+#include <qpa/qwindowsysteminterface.h>
+#include <QtCore/qcoreapplication.h>
+
+#include <emscripten/bind.h>
+
+// this is where EGL headers are pulled in, make sure it is last
+#include "qwasmscreen.h"
+
+using namespace emscripten;
+QT_BEGIN_NAMESPACE
+
+void browserBeforeUnload()
+{
+ QWasmIntegration::QWasmBrowserExit();
+}
+
+EMSCRIPTEN_BINDINGS(my_module)
+{
+ function("browserBeforeUnload", &browserBeforeUnload);
+}
+
+static QWasmIntegration *globalHtml5Integration;
+QWasmIntegration *QWasmIntegration::get() { return globalHtml5Integration; }
+
+QWasmIntegration::QWasmIntegration()
+ : m_fontDb(nullptr),
+ m_compositor(new QWasmCompositor),
+ m_screen(new QWasmScreen(m_compositor)),
+ m_eventDispatcher(nullptr)
+{
+
+ globalHtml5Integration = this;
+
+ updateQScreenAndCanvasRenderSize();
+ screenAdded(m_screen);
+ emscripten_set_resize_callback(0, (void *)this, 1, uiEvent_cb);
+
+ m_eventTranslator = new QWasmEventTranslator;
+
+ EM_ASM(// exit app if browser closes
+ window.onbeforeunload = function () {
+ Module.browserBeforeUnload();
+ };
+ );
+}
+
+QWasmIntegration::~QWasmIntegration()
+{
+ delete m_compositor;
+ destroyScreen(m_screen);
+ delete m_fontDb;
+ delete m_eventTranslator;
+}
+
+void QWasmIntegration::QWasmBrowserExit()
+{
+ QCoreApplication *app = QCoreApplication::instance();
+ app->quit();
+}
+
+bool QWasmIntegration::hasCapability(QPlatformIntegration::Capability cap) const
+{
+ switch (cap) {
+ case ThreadedPixmaps: return true;
+ case OpenGL: return true;
+ case ThreadedOpenGL: return true;
+ case RasterGLSurface: return false; // to enable this you need to fix qopenglwidget and quickwidget for wasm
+ case MultipleWindows: return true;
+ case WindowManagement: return true;
+ default: return QPlatformIntegration::hasCapability(cap);
+ }
+}
+
+QPlatformWindow *QWasmIntegration::createPlatformWindow(QWindow *window) const
+{
+ return new QWasmWindow(window, m_compositor, m_backingStores.value(window));
+}
+
+QPlatformBackingStore *QWasmIntegration::createPlatformBackingStore(QWindow *window) const
+{
+#ifndef QT_NO_OPENGL
+ QWasmBackingStore *backingStore = new QWasmBackingStore(m_compositor, window);
+ m_backingStores.insert(window, backingStore);
+ return backingStore;
+#else
+ return nullptr;
+#endif
+}
+
+#ifndef QT_NO_OPENGL
+QPlatformOpenGLContext *QWasmIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
+{
+ return new QWasmOpenGLContext(context->format());
+}
+#endif
+
+QPlatformFontDatabase *QWasmIntegration::fontDatabase() const
+{
+ if (m_fontDb == nullptr)
+ m_fontDb = new QWasmFontDatabase;
+
+ return m_fontDb;
+}
+
+QAbstractEventDispatcher *QWasmIntegration::createEventDispatcher() const
+{
+ return new QWasmEventDispatcher;
+}
+
+QVariant QWasmIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
+{
+ return QPlatformIntegration::styleHint(hint);
+}
+
+QStringList QWasmIntegration::themeNames() const
+{
+ return QStringList() << QLatin1String("webassembly");
+}
+
+QPlatformTheme *QWasmIntegration::createPlatformTheme(const QString &name) const
+{
+ if (name == QLatin1String("webassembly"))
+ return new QWasmTheme;
+ return QPlatformIntegration::createPlatformTheme(name);
+}
+
+int QWasmIntegration::uiEvent_cb(int eventType, const EmscriptenUiEvent *e, void *userData)
+{
+ Q_UNUSED(e)
+ Q_UNUSED(userData)
+
+ if (eventType == EMSCRIPTEN_EVENT_RESIZE) {
+ // This resize event is called when the HTML window is resized. Depending
+ // on the page layout the the canvas might also have been resized, so we
+ // update the Qt screen size (and canvas render size).
+ updateQScreenAndCanvasRenderSize();
+ }
+
+ return 0;
+}
+
+static void set_canvas_size(double width, double height)
+{
+ EM_ASM_({
+ var canvas = Module.canvas;
+ canvas.width = $0;
+ canvas.height = $1;
+ }, width, height);
+}
+
+void QWasmIntegration::updateQScreenAndCanvasRenderSize()
+{
+ // The HTML canvas has two sizes: the CSS size and the canvas render size.
+ // The CSS size is determined according to standard CSS rules, while the
+ // render size is set using the "width" and "height" attributes. The render
+ // size must be set manually and is not auto-updated on CSS size change.
+ // Setting the render size to a value larger than the CSS size enables high-dpi
+ // rendering.
+
+ double css_width;
+ double css_height;
+ emscripten_get_element_css_size(0, &css_width, &css_height);
+ QSizeF cssSize(css_width, css_height);
+
+ QWasmScreen *screen = QWasmIntegration::get()->m_screen;
+ QSizeF canvasSize = cssSize * screen->devicePixelRatio();
+
+ set_canvas_size(canvasSize.width(), canvasSize.height());
+ screen->setGeometry(QRect(QPoint(0, 0), cssSize.toSize()));
+ QWasmIntegration::get()->m_compositor->redrawWindowContent();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h
new file mode 100644
index 0000000000..ebc3d9d431
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmintegration.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWASMINTEGRATION_H
+#define QWASMINTEGRATION_H
+
+#include "qwasmwindow.h"
+
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformscreen.h>
+
+#include <QtCore/qhash.h>
+
+#include <emscripten.h>
+#include <emscripten/html5.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWasmEventTranslator;
+class QWasmFontDatabase;
+class QWasmWindow;
+class QWasmEventDispatcher;
+class QWasmScreen;
+class QWasmCompositor;
+class QWasmBackingStore;
+
+class QWasmIntegration : public QObject, public QPlatformIntegration
+{
+ Q_OBJECT
+public:
+ QWasmIntegration();
+ ~QWasmIntegration();
+
+ bool hasCapability(QPlatformIntegration::Capability cap) const override;
+ QPlatformWindow *createPlatformWindow(QWindow *window) const override;
+ QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
+#ifndef QT_NO_OPENGL
+ QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
+#endif
+ QPlatformFontDatabase *fontDatabase() const override;
+ QAbstractEventDispatcher *createEventDispatcher() const override;
+ QVariant styleHint(QPlatformIntegration::StyleHint hint) const override;
+ QStringList themeNames() const override;
+ QPlatformTheme *createPlatformTheme(const QString &name) const override;
+
+ static QWasmIntegration *get();
+ QWasmScreen *screen() { return m_screen; }
+ QWasmCompositor *compositor() { return m_compositor; }
+ QWasmEventTranslator *eventTranslator() { return m_eventTranslator; }
+
+ static void QWasmBrowserExit();
+ static void updateQScreenAndCanvasRenderSize();
+
+private:
+ mutable QWasmFontDatabase *m_fontDb;
+ QWasmCompositor *m_compositor;
+ mutable QWasmScreen *m_screen;
+ mutable QWasmEventTranslator *m_eventTranslator;
+ mutable QWasmEventDispatcher *m_eventDispatcher;
+ static int uiEvent_cb(int eventType, const EmscriptenUiEvent *e, void *userData);
+ mutable QHash<QWindow *, QWasmBackingStore *> m_backingStores;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWASMINTEGRATION_H
diff --git a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp
new file mode 100644
index 0000000000..73af3d1878
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwasmopenglcontext.h"
+
+#include <EGL/egl.h>
+
+QT_BEGIN_NAMESPACE
+
+QWasmOpenGLContext::QWasmOpenGLContext(const QSurfaceFormat &format)
+ : m_requestedFormat(format)
+{
+ m_requestedFormat.setRenderableType(QSurfaceFormat::OpenGLES);
+}
+
+QWasmOpenGLContext::~QWasmOpenGLContext()
+{
+ if (m_context)
+ emscripten_webgl_destroy_context(m_context);
+}
+
+void QWasmOpenGLContext::maybeRecreateEmscriptenContext(QPlatformSurface *surface)
+{
+ // Native emscripten contexts are tied to a single surface. Recreate
+ // the context if the surface is changed.
+ if (surface != m_surface) {
+ m_surface = surface;
+
+ // Destroy existing context
+ if (m_context)
+ emscripten_webgl_destroy_context(m_context);
+
+ // Create new context
+ const char *canvasId = 0; // (use default canvas) FIXME: get the actual canvas from the surface.
+ m_context = createEmscriptenContext(canvasId, m_requestedFormat);
+
+ // Register context-lost callback.
+ auto callback = [](int eventType, const void *reserved, void *userData) -> EM_BOOL
+ {
+ Q_UNUSED(eventType);
+ Q_UNUSED(reserved);
+ // The application may get contex-lost if e.g. moved to the background. Set
+ // m_contextLost which will make isValid() return false. Application code will
+ // then detect this and recrate the the context, resulting in a new QWasmOpenGLContext
+ // instance.
+ reinterpret_cast<QWasmOpenGLContext *>(userData)->m_contextLost = true;
+ return true;
+ };
+ bool capture = true;
+ emscripten_set_webglcontextlost_callback(canvasId, this, capture, callback);
+ }
+}
+
+EMSCRIPTEN_WEBGL_CONTEXT_HANDLE QWasmOpenGLContext::createEmscriptenContext(const char *canvasId, QSurfaceFormat format)
+{
+ EmscriptenWebGLContextAttributes attributes;
+ emscripten_webgl_init_context_attributes(&attributes); // Populate with default attributes
+
+ attributes.preferLowPowerToHighPerformance = false;
+ attributes.failIfMajorPerformanceCaveat = false;
+ attributes.antialias = true;
+ attributes.enableExtensionsByDefault = true;
+
+ if (format.majorVersion() == 3) {
+ attributes.majorVersion = 2;
+ }
+
+ // WebGL offers enable/disable control but not size control for these
+ attributes.alpha = format.alphaBufferSize() > 0;
+ attributes.depth = format.depthBufferSize() > 0;
+ attributes.stencil = format.stencilBufferSize() > 0;
+
+ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context(canvasId, &attributes);
+
+ return context;
+}
+
+QSurfaceFormat QWasmOpenGLContext::format() const
+{
+ return m_requestedFormat;
+}
+
+GLuint QWasmOpenGLContext::defaultFramebufferObject(QPlatformSurface *surface) const
+{
+ return QPlatformOpenGLContext::defaultFramebufferObject(surface);
+}
+
+bool QWasmOpenGLContext::makeCurrent(QPlatformSurface *surface)
+{
+ maybeRecreateEmscriptenContext(surface);
+
+ return emscripten_webgl_make_context_current(m_context) == EMSCRIPTEN_RESULT_SUCCESS;
+}
+
+void QWasmOpenGLContext::swapBuffers(QPlatformSurface *surface)
+{
+ Q_UNUSED(surface);
+ // No swapbuffers on WebGl
+}
+
+void QWasmOpenGLContext::doneCurrent()
+{
+ // No doneCurrent on WebGl
+}
+
+bool QWasmOpenGLContext::isSharing() const
+{
+ return false;
+}
+
+bool QWasmOpenGLContext::isValid() const
+{
+ return (m_contextLost == false);
+}
+
+QFunctionPointer QWasmOpenGLContext::getProcAddress(const char *procName)
+{
+ return reinterpret_cast<QFunctionPointer>(eglGetProcAddress(procName));
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmopenglcontext.h b/src/plugins/platforms/wasm/qwasmopenglcontext.h
new file mode 100644
index 0000000000..9123100479
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmopenglcontext.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qpa/qplatformopenglcontext.h>
+
+#include <emscripten.h>
+#include <emscripten/html5.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWasmOpenGLContext : public QPlatformOpenGLContext
+{
+public:
+ QWasmOpenGLContext(const QSurfaceFormat &format);
+ ~QWasmOpenGLContext();
+
+ QSurfaceFormat format() const override;
+ void swapBuffers(QPlatformSurface *surface) override;
+ GLuint defaultFramebufferObject(QPlatformSurface *surface) const override;
+ bool makeCurrent(QPlatformSurface *surface) override;
+ void doneCurrent() override;
+ bool isSharing() const override;
+ bool isValid() const override;
+ QFunctionPointer getProcAddress(const char *procName) override;
+
+private:
+ void maybeRecreateEmscriptenContext(QPlatformSurface *surface);
+ static EMSCRIPTEN_WEBGL_CONTEXT_HANDLE createEmscriptenContext(const char *canvasId, QSurfaceFormat format);
+
+ bool m_contextLost = false;
+ QSurfaceFormat m_requestedFormat;
+ QPlatformSurface *m_surface = nullptr;
+ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE m_context = 0;
+};
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/platforms/wasm/qwasmscreen.cpp b/src/plugins/platforms/wasm/qwasmscreen.cpp
new file mode 100644
index 0000000000..93e9906ffc
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmscreen.cpp
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwasmscreen.h"
+#include "qwasmwindow.h"
+#include "qwasmcompositor.h"
+
+#include <QtEglSupport/private/qeglconvenience_p.h>
+#ifndef QT_NO_OPENGL
+# include <QtEglSupport/private/qeglplatformcontext_p.h>
+#endif
+#include <qpa/qwindowsysteminterface.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtGui/qguiapplication.h>
+#include <private/qhighdpiscaling_p.h>
+
+
+QT_BEGIN_NAMESPACE
+
+QWasmScreen::QWasmScreen(QWasmCompositor *compositor)
+ : m_compositor(compositor)
+ , m_depth(32)
+ , m_format(QImage::Format_RGB32)
+{
+ m_compositor->setScreen(this);
+}
+
+QWasmScreen::~QWasmScreen()
+{
+
+}
+
+QRect QWasmScreen::geometry() const
+{
+ return m_geometry;
+}
+
+int QWasmScreen::depth() const
+{
+ return m_depth;
+}
+
+QImage::Format QWasmScreen::format() const
+{
+ return m_format;
+}
+
+qreal QWasmScreen::devicePixelRatio() const
+{
+ // FIXME: The effective device pixel ratio may be different from the
+ // HTML window dpr if the OpenGL driver/GPU allocates a less than
+ // full resolution surface. Use emscripten_webgl_get_drawing_buffer_size()
+ // and compute the dpr instead.
+ double htmlWindowDpr = EM_ASM_DOUBLE({
+ return window.devicePixelRatio;
+ });
+ return qreal(htmlWindowDpr);
+}
+
+QPlatformCursor *QWasmScreen::cursor() const
+{
+ return const_cast<QWasmCursor *>(&m_cursor);
+}
+
+void QWasmScreen::resizeMaximizedWindows()
+{
+ QPlatformScreen::resizeMaximizedWindows();
+}
+
+QWindow *QWasmScreen::topWindow() const
+{
+ return m_compositor->keyWindow();
+}
+
+QWindow *QWasmScreen::topLevelAt(const QPoint &p) const
+{
+ return m_compositor->windowAt(p);
+}
+
+void QWasmScreen::invalidateSize()
+{
+ m_geometry = QRect();
+}
+
+void QWasmScreen::setGeometry(const QRect &rect)
+{
+ m_geometry = rect;
+ QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(), availableGeometry());
+ resizeMaximizedWindows();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmscreen.h b/src/plugins/platforms/wasm/qwasmscreen.h
new file mode 100644
index 0000000000..3891db77bb
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmscreen.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWASMSCREEN_H
+#define QWASMSCREEN_H
+
+#include "qwasmcursor.h"
+
+#include <qpa/qplatformscreen.h>
+
+#include <QtCore/qscopedpointer.h>
+#include <QtCore/qtextstream.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPlatformOpenGLContext;
+class QWasmWindow;
+class QWasmBackingStore;
+class QWasmCompositor;
+class QOpenGLContext;
+
+class QWasmScreen : public QObject, public QPlatformScreen
+{
+ Q_OBJECT
+public:
+
+ QWasmScreen(QWasmCompositor *compositor);
+ ~QWasmScreen();
+
+ QRect geometry() const override;
+ int depth() const override;
+ QImage::Format format() const override;
+ qreal devicePixelRatio() const override;
+ QPlatformCursor *cursor() const override;
+
+ void resizeMaximizedWindows();
+ QWindow *topWindow() const;
+ QWindow *topLevelAt(const QPoint &p) const override;
+
+ void invalidateSize();
+
+public slots:
+ void setGeometry(const QRect &rect);
+protected:
+
+private:
+ QWasmCompositor *m_compositor;
+
+ QRect m_geometry = QRect(0, 0, 100, 100);
+ int m_depth;
+ QImage::Format m_format;
+ QWasmCursor m_cursor;
+};
+
+QT_END_NAMESPACE
+#endif // QWASMSCREEN_H
diff --git a/src/plugins/platforms/wasm/qwasmstylepixmaps_p.h b/src/plugins/platforms/wasm/qwasmstylepixmaps_p.h
new file mode 100644
index 0000000000..2b5860f42f
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmstylepixmaps_p.h
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWASMSTYLEPIXMAPS_P_H
+#define QWASMSTYLEPIXMAPS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+/* XPM */
+static const char * const qt_menu_xpm[] = {
+"16 16 72 1",
+" c None",
+". c #65AF36",
+"+ c #66B036",
+"@ c #77B94C",
+"# c #A7D28C",
+"$ c #BADBA4",
+"% c #A4D088",
+"& c #72B646",
+"* c #9ACB7A",
+"= c #7FBD56",
+"- c #85C05F",
+"; c #F4F9F0",
+"> c #FFFFFF",
+", c #E5F1DC",
+"' c #ECF5E7",
+") c #7ABA50",
+"! c #83BF5C",
+"~ c #AED595",
+"{ c #D7EACA",
+"] c #A9D28D",
+"^ c #BCDDA8",
+"/ c #C4E0B1",
+"( c #81BE59",
+"_ c #D0E7C2",
+": c #D4E9C6",
+"< c #6FB542",
+"[ c #6EB440",
+"} c #88C162",
+"| c #98CA78",
+"1 c #F4F9F1",
+"2 c #8FC56C",
+"3 c #F1F8EC",
+"4 c #E8F3E1",
+"5 c #D4E9C7",
+"6 c #74B748",
+"7 c #80BE59",
+"8 c #73B747",
+"9 c #6DB43F",
+"0 c #CBE4BA",
+"a c #80BD58",
+"b c #6DB33F",
+"c c #FEFFFE",
+"d c #68B138",
+"e c #F9FCF7",
+"f c #91C66F",
+"g c #E8F3E0",
+"h c #DCEDD0",
+"i c #91C66E",
+"j c #A3CF86",
+"k c #C9E3B8",
+"l c #B0D697",
+"m c #E3F0DA",
+"n c #95C873",
+"o c #E6F2DE",
+"p c #9ECD80",
+"q c #BEDEAA",
+"r c #C7E2B6",
+"s c #79BA4F",
+"t c #6EB441",
+"u c #BCDCA7",
+"v c #FAFCF8",
+"w c #F6FAF3",
+"x c #84BF5D",
+"y c #EDF6E7",
+"z c #FAFDF9",
+"A c #88C263",
+"B c #98CA77",
+"C c #CDE5BE",
+"D c #67B037",
+"E c #D9EBCD",
+"F c #6AB23C",
+"G c #77B94D",
+" .++++++++++++++",
+".+++++++++++++++",
+"+++@#$%&+++*=+++",
+"++-;>,>')+!>~+++",
+"++{>]+^>/(_>:~<+",
+"+[>>}+|>123>456+",
+"+7>>8+->>90>~+++",
+"+a>>b+a>c[0>~+++",
+"+de>=+f>g+0>~+++",
+"++h>i+j>k+0>~+++",
+"++l>mno>p+q>rst+",
+"++duv>wl++xy>zA+",
+"++++B>Cb++++&D++",
+"+++++0zE++++++++",
+"++++++FG+++++++.",
+"++++++++++++++. "};
+
+static const char * const qt_close_xpm[] = {
+"10 10 2 1",
+"# c #000000",
+". c None",
+"..........",
+".##....##.",
+"..##..##..",
+"...####...",
+"....##....",
+"...####...",
+"..##..##..",
+".##....##.",
+"..........",
+".........."};
+
+static const char * const qt_maximize_xpm[]={
+"10 10 2 1",
+"# c #000000",
+". c None",
+"#########.",
+"#########.",
+"#.......#.",
+"#.......#.",
+"#.......#.",
+"#.......#.",
+"#.......#.",
+"#.......#.",
+"#########.",
+".........."};
+
+
+static const char * const qt_normalizeup_xpm[] = {
+"10 10 2 1",
+"# c #000000",
+". c None",
+"...######.",
+"...######.",
+"...#....#.",
+".######.#.",
+".######.#.",
+".#....###.",
+".#....#...",
+".#....#...",
+".######...",
+".........."};
+
+
+#endif // QWASMSTYLEPIXMAPS_P_H
diff --git a/src/plugins/platforms/wasm/qwasmtheme.cpp b/src/plugins/platforms/wasm/qwasmtheme.cpp
new file mode 100644
index 0000000000..a7f2db3bd3
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmtheme.cpp
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwasmtheme.h"
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+QWasmTheme::QWasmTheme()
+{
+}
+
+QWasmTheme::~QWasmTheme()
+{
+}
+
+QVariant QWasmTheme::themeHint(ThemeHint hint) const
+{
+ if (hint == QPlatformTheme::StyleNames)
+ return QVariant(QStringList() << QLatin1String("fusion"));
+ return QPlatformTheme::themeHint(hint);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmtheme.h b/src/plugins/platforms/wasm/qwasmtheme.h
new file mode 100644
index 0000000000..e4cc06e049
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmtheme.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWASMTHEME_H
+#define QWASMTHEME_H
+
+#include <qpa/qplatformtheme.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWasmEventTranslator;
+class QWasmFontDatabase;
+class QWasmWindow;
+class QWasmEventDispatcher;
+class QWasmScreen;
+class QWasmCompositor;
+class QWasmBackingStore;
+
+class QWasmTheme : public QPlatformTheme
+{
+public:
+ QWasmTheme();
+ ~QWasmTheme();
+
+ QVariant themeHint(ThemeHint hint) const override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWASMTHEME_H
diff --git a/src/plugins/platforms/wasm/qwasmwindow.cpp b/src/plugins/platforms/wasm/qwasmwindow.cpp
new file mode 100644
index 0000000000..0489813929
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmwindow.cpp
@@ -0,0 +1,398 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qpa/qwindowsysteminterface.h>
+#include <private/qguiapplication_p.h>
+#include <QtGui/private/qopenglcontext_p.h>
+#include <QtGui/private/qwindow_p.h>
+#include <QtGui/qopenglcontext.h>
+
+#include "qwasmwindow.h"
+#include "qwasmscreen.h"
+#include "qwasmcompositor.h"
+#include "qwasmeventdispatcher.h"
+
+#include <iostream>
+
+Q_GUI_EXPORT int qt_defaultDpiX();
+
+QT_BEGIN_NAMESPACE
+
+QWasmWindow::QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingStore *backingStore)
+ : QPlatformWindow(w),
+ m_window(w),
+ m_compositor(compositor),
+ m_backingStore(backingStore)
+{
+ m_needsCompositor = w->surfaceType() != QSurface::OpenGLSurface;
+ static int serialNo = 0;
+ m_winid = ++serialNo;
+ qWarning("QWasmWindow %p: %p 0x%x\n", this, w, uint(m_winid));
+
+ m_compositor->addWindow(this);
+
+ // Pure OpenGL windows draw directly using egl, disable the compositor.
+ m_compositor->setEnabled(w->surfaceType() != QSurface::OpenGLSurface);
+}
+
+QWasmWindow::~QWasmWindow()
+{
+ m_compositor->removeWindow(this);
+}
+
+void QWasmWindow::initialize()
+{
+ QRect rect = windowGeometry();
+
+ QPlatformWindow::setGeometry(rect);
+
+ const QSize minimumSize = windowMinimumSize();
+ if (rect.width() > 0 || rect.height() > 0) {
+ rect.setWidth(qBound(1, rect.width(), 2000));
+ rect.setHeight(qBound(1, rect.height(), 2000));
+ } else if (minimumSize.width() > 0 || minimumSize.height() > 0) {
+ rect.setSize(minimumSize);
+ }
+
+ setWindowState(window()->windowStates());
+ setWindowFlags(window()->flags());
+ setWindowTitle(window()->title());
+ m_hasTitle = window()->flags().testFlag(Qt::WindowTitleHint) && m_needsCompositor;
+
+ if (window()->isTopLevel())
+ setWindowIcon(window()->icon());
+ m_normalGeometry = rect;
+}
+
+QWasmScreen *QWasmWindow::platformScreen() const
+{
+ return static_cast<QWasmScreen *>(window()->screen()->handle());
+}
+
+void QWasmWindow::setGeometry(const QRect &rect)
+{
+ QRect r = rect;
+ if (m_needsCompositor) {
+ int yMin = window()->geometry().top() - window()->frameGeometry().top();
+
+ if (r.y() < yMin)
+ r.moveTop(yMin);
+ }
+ QWindowSystemInterface::handleGeometryChange(window(), r);
+ QPlatformWindow::setGeometry(r);
+
+ QWindowSystemInterface::flushWindowSystemEvents();
+ invalidate();
+}
+
+void QWasmWindow::setVisible(bool visible)
+{
+ QRect newGeom;
+
+ if (visible) {
+ const bool forceFullScreen = !m_needsCompositor;//make gl apps fullscreen for now
+
+ if (forceFullScreen || (m_windowState & Qt::WindowFullScreen))
+ newGeom = platformScreen()->geometry();
+ else if (m_windowState & Qt::WindowMaximized)
+ newGeom = platformScreen()->availableGeometry();
+ }
+ QPlatformWindow::setVisible(visible);
+
+ m_compositor->setVisible(this, visible);
+
+ if (!newGeom.isEmpty())
+ setGeometry(newGeom); // may or may not generate an expose
+
+ invalidate();
+}
+
+QMargins QWasmWindow::frameMargins() const
+{
+ int border = m_hasTitle ? 4. * (qreal(qt_defaultDpiX()) / 96.0) : 0;
+ int titleBarHeight = m_hasTitle ? titleHeight() : 0;
+
+ QMargins margins;
+ margins.setLeft(border);
+ margins.setRight(border);
+ margins.setTop(2*border + titleBarHeight);
+ margins.setBottom(border);
+
+ return margins;
+}
+
+void QWasmWindow::raise()
+{
+ m_compositor->raise(this);
+ QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size()));
+ invalidate();
+}
+
+void QWasmWindow::lower()
+{
+ m_compositor->lower(this);
+ QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size()));
+ invalidate();
+}
+
+WId QWasmWindow::winId() const
+{
+ return m_winid;
+}
+
+void QWasmWindow::propagateSizeHints()
+{
+// get rid of base class warning
+}
+
+void QWasmWindow::injectMousePressed(const QPoint &local, const QPoint &global,
+ Qt::MouseButton button, Qt::KeyboardModifiers mods)
+{
+ Q_UNUSED(local);
+ Q_UNUSED(mods);
+
+ if (!m_hasTitle || button != Qt::LeftButton)
+ return;
+
+ if (maxButtonRect().contains(global))
+ m_activeControl = QWasmCompositor::SC_TitleBarMaxButton;
+ else if (minButtonRect().contains(global))
+ m_activeControl = QWasmCompositor::SC_TitleBarMinButton;
+ else if (closeButtonRect().contains(global))
+ m_activeControl = QWasmCompositor::SC_TitleBarCloseButton;
+ else if (normButtonRect().contains(global))
+ m_activeControl = QWasmCompositor::SC_TitleBarNormalButton;
+
+ invalidate();
+}
+
+void QWasmWindow::injectMouseReleased(const QPoint &local, const QPoint &global,
+ Qt::MouseButton button, Qt::KeyboardModifiers mods)
+{
+ Q_UNUSED(local);
+ Q_UNUSED(mods);
+
+ if (!m_hasTitle || button != Qt::LeftButton)
+ return;
+
+ if (closeButtonRect().contains(global) && m_activeControl == QWasmCompositor::SC_TitleBarCloseButton)
+ window()->close();
+
+ if (maxButtonRect().contains(global) && m_activeControl == QWasmCompositor::SC_TitleBarMaxButton) {
+ window()->setWindowState(Qt::WindowMaximized);
+ platformScreen()->resizeMaximizedWindows();
+ }
+
+ if (normButtonRect().contains(global) && m_activeControl == QWasmCompositor::SC_TitleBarNormalButton) {
+ window()->setWindowState(Qt::WindowNoState);
+ setGeometry(normalGeometry());
+ }
+
+ m_activeControl = QWasmCompositor::SC_None;
+
+ invalidate();
+}
+
+int QWasmWindow::titleHeight() const
+{
+ return 18. * (qreal(qt_defaultDpiX()) / 96.0);//dpiScaled(18.);
+}
+
+int QWasmWindow::borderWidth() const
+{
+ return 4. * (qreal(qt_defaultDpiX()) / 96.0);// dpiScaled(4.);
+}
+
+QRegion QWasmWindow::titleGeometry() const
+{
+ int border = borderWidth();
+
+ QRegion result(window()->frameGeometry().x() + border,
+ window()->frameGeometry().y() + border,
+ window()->frameGeometry().width() - 2*border,
+ titleHeight());
+
+ result -= titleControlRegion();
+
+ return result;
+}
+
+QRegion QWasmWindow::resizeRegion() const
+{
+ int border = borderWidth();
+ QRegion result(window()->frameGeometry().adjusted(-border, -border, border, border));
+ result -= window()->frameGeometry().adjusted(border, border, -border, -border);
+
+ return result;
+}
+
+bool QWasmWindow::isPointOnTitle(QPoint point) const
+{
+ bool ok = titleGeometry().contains(point);
+ return ok;
+}
+
+bool QWasmWindow::isPointOnResizeRegion(QPoint point) const
+{
+ return resizeRegion().contains(point);
+}
+
+QWasmWindow::ResizeMode QWasmWindow::resizeModeAtPoint(QPoint point) const
+{
+ QPoint p1 = window()->frameGeometry().topLeft() - QPoint(5, 5);
+ QPoint p2 = window()->frameGeometry().bottomRight() + QPoint(5, 5);
+ int corner = 20;
+
+ QRect top(p1, QPoint(p2.x(), p1.y() + corner));
+ QRect middle(QPoint(p1.x(), p1.y() + corner), QPoint(p2.x(), p2.y() - corner));
+ QRect bottom(QPoint(p1.x(), p2.y() - corner), p2);
+
+ QRect left(p1, QPoint(p1.x() + corner, p2.y()));
+ QRect center(QPoint(p1.x() + corner, p1.y()), QPoint(p2.x() - corner, p2.y()));
+ QRect right(QPoint(p2.x() - corner, p1.y()), p2);
+
+ if (top.contains(point)) {
+ // Top
+ if (left.contains(point))
+ return ResizeTopLeft;
+ if (center.contains(point))
+ return ResizeTop;
+ if (right.contains(point))
+ return ResizeTopRight;
+ } else if (middle.contains(point)) {
+ // Middle
+ if (left.contains(point))
+ return ResizeLeft;
+ if (right.contains(point))
+ return ResizeRight;
+ } else if (bottom.contains(point)) {
+ // Bottom
+ if (left.contains(point))
+ return ResizeBottomLeft;
+ if (center.contains(point))
+ return ResizeBottom;
+ if (right.contains(point))
+ return ResizeBottomRight;
+ }
+
+ return ResizeNone;
+}
+
+QRect getSubControlRect(const QWasmWindow *window, QWasmCompositor::SubControls subControl)
+{
+ QWasmCompositor::QWasmTitleBarOptions options = QWasmCompositor::makeTitleBarOptions(window);
+
+ QRect r = QWasmCompositor::titlebarRect(options, subControl);
+ r.translate(window->window()->frameGeometry().x(), window->window()->frameGeometry().y());
+
+ return r;
+}
+
+QRect QWasmWindow::maxButtonRect() const
+{
+ return getSubControlRect(this, QWasmCompositor::SC_TitleBarMaxButton);
+}
+
+QRect QWasmWindow::minButtonRect() const
+{
+ return getSubControlRect(this, QWasmCompositor::SC_TitleBarMinButton);
+}
+
+QRect QWasmWindow::closeButtonRect() const
+{
+ return getSubControlRect(this, QWasmCompositor::SC_TitleBarCloseButton);
+}
+
+QRect QWasmWindow::normButtonRect() const
+{
+ return getSubControlRect(this, QWasmCompositor::SC_TitleBarNormalButton);
+}
+
+QRect QWasmWindow::sysMenuRect() const
+{
+ return getSubControlRect(this, QWasmCompositor::SC_TitleBarSysMenu);
+}
+
+QRegion QWasmWindow::titleControlRegion() const
+{
+ QRegion result;
+ result += closeButtonRect();
+ result += minButtonRect();
+ result += maxButtonRect();
+ result += sysMenuRect();
+
+ return result;
+}
+
+void QWasmWindow::invalidate()
+{
+ m_compositor->requestRedraw();
+}
+
+QWasmCompositor::SubControls QWasmWindow::activeSubControl() const
+{
+ return m_activeControl;
+}
+
+void QWasmWindow::setWindowState(Qt::WindowStates states)
+{
+ m_windowState = Qt::WindowNoState;
+ if (states & Qt::WindowMinimized)
+ m_windowState = Qt::WindowMinimized;
+ else if (states & Qt::WindowFullScreen)
+ m_windowState = Qt::WindowFullScreen;
+ else if (states & Qt::WindowMaximized)
+ m_windowState = Qt::WindowMaximized;
+}
+
+QRect QWasmWindow::normalGeometry() const
+{
+ return m_normalGeometry;
+}
+
+qreal QWasmWindow::devicePixelRatio() const
+{
+ return screen()->devicePixelRatio();
+}
+
+void QWasmWindow::requestUpdate()
+{
+ QPointer<QWindow> windowPointer(window());
+ bool registered = QWasmEventDispatcher::registerRequestUpdateCallback([=](){
+ if (windowPointer.isNull())
+ return;
+
+ deliverUpdateRequest();
+ });
+
+ if (!registered)
+ QPlatformWindow::requestUpdate();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmwindow.h b/src/plugins/platforms/wasm/qwasmwindow.h
new file mode 100644
index 0000000000..a0c463e796
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmwindow.h
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWASMWINDOW_H
+#define QWASMWINDOW_H
+
+#include "qwasmintegration.h"
+#include <qpa/qplatformwindow.h>
+#include <emscripten/html5.h>
+#include "qwasmbackingstore.h"
+#include "qwasmscreen.h"
+#include "qwasmcompositor.h"
+
+QT_BEGIN_NAMESPACE
+
+class QWasmCompositor;
+
+class QWasmWindow : public QPlatformWindow
+{
+public:
+ enum ResizeMode {
+ ResizeNone,
+ ResizeTopLeft,
+ ResizeTop,
+ ResizeTopRight,
+ ResizeRight,
+ ResizeBottomRight,
+ ResizeBottom,
+ ResizeBottomLeft,
+ ResizeLeft
+ };
+
+ QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingStore *backingStore);
+ ~QWasmWindow();
+
+ void initialize() override;
+
+ void setGeometry(const QRect &) override;
+ void setVisible(bool visible) override;
+ QMargins frameMargins() const override;
+
+ WId winId() const override;
+
+ void propagateSizeHints() override;
+ void raise() override;
+ void lower() override;
+ QRect normalGeometry() const override;
+ qreal devicePixelRatio() const override;
+ void requestUpdate() override;
+
+ QWasmScreen *platformScreen() const;
+ void setBackingStore(QWasmBackingStore *store) { m_backingStore = store; }
+ QWasmBackingStore *backingStore() const { return m_backingStore; }
+ QWindow *window() const { return m_window; }
+
+ void injectMousePressed(const QPoint &local, const QPoint &global,
+ Qt::MouseButton button, Qt::KeyboardModifiers mods);
+ void injectMouseReleased(const QPoint &local, const QPoint &global,
+ Qt::MouseButton button, Qt::KeyboardModifiers mods);
+
+ int titleHeight() const;
+ int borderWidth() const;
+ QRegion titleGeometry() const;
+ QRegion resizeRegion() const;
+ bool isPointOnTitle(QPoint point) const;
+ bool isPointOnResizeRegion(QPoint point) const;
+ ResizeMode resizeModeAtPoint(QPoint point) const;
+ QRect maxButtonRect() const;
+ QRect minButtonRect() const;
+ QRect closeButtonRect() const;
+ QRect sysMenuRect() const;
+ QRect normButtonRect() const;
+ QRegion titleControlRegion() const;
+ QWasmCompositor::SubControls activeSubControl() const;
+
+ void setWindowState(Qt::WindowStates state) override;
+ bool setKeyboardGrabEnabled(bool) override { return false; }
+ bool setMouseGrabEnabled(bool) override { return false; }
+
+protected:
+ void invalidate();
+
+protected:
+ friend class QWasmScreen;
+
+ QWindow* m_window = nullptr;
+ QWasmCompositor *m_compositor = nullptr;
+ QWasmBackingStore *m_backingStore = nullptr;
+ QRect m_normalGeometry {0, 0, 0 ,0};
+
+ Qt::WindowState m_windowState = Qt::WindowNoState;
+ QWasmCompositor::SubControls m_activeControl = QWasmCompositor::SC_None;
+ WId m_winid = 0;
+ bool m_hasTitle = false;
+ bool m_needsCompositor = false;
+};
+QT_END_NAMESPACE
+#endif // QWASMWINDOW_H
diff --git a/src/plugins/platforms/wasm/wasm.json b/src/plugins/platforms/wasm/wasm.json
new file mode 100644
index 0000000000..6e700e06b9
--- /dev/null
+++ b/src/plugins/platforms/wasm/wasm.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "wasm" ]
+}
diff --git a/src/plugins/platforms/wasm/wasm.pro b/src/plugins/platforms/wasm/wasm.pro
new file mode 100644
index 0000000000..f1205702ef
--- /dev/null
+++ b/src/plugins/platforms/wasm/wasm.pro
@@ -0,0 +1,65 @@
+TARGET = wasm
+CONFIG += static plugin
+QT += \
+ core-private gui-private \
+ eventdispatcher_support-private fontdatabase_support-private egl_support-private
+
+# Avoid X11 header collision, use generic EGL native types
+DEFINES += QT_EGL_NO_X11
+
+SOURCES = \
+ main.cpp \
+ qwasmintegration.cpp \
+ qwasmwindow.cpp \
+ qwasmscreen.cpp \
+ qwasmfontdatabase.cpp \
+ qwasmeventtranslator.cpp \
+ qwasmeventdispatcher.cpp \
+ qwasmcompositor.cpp \
+ qwasmcursor.cpp \
+ qwasmopenglcontext.cpp \
+ qwasmtheme.cpp
+
+HEADERS = \
+ qwasmintegration.h \
+ qwasmwindow.h \
+ qwasmscreen.h \
+ qwasmfontdatabase.h \
+ qwasmeventtranslator.h \
+ qwasmeventdispatcher.h \
+ qwasmcompositor.h \
+ qwasmstylepixmaps_p.h \
+ qwasmcursor.h \
+ qwasmopenglcontext.h \
+ qwasmtheme.h
+
+wasmfonts.files = \
+ ../../../3rdparty/wasm/Vera.ttf \
+ ../../../3rdparty/wasm/DejaVuSans.ttf
+wasmfonts.prefix = /fonts
+wasmfonts.base = ../../../3rdparty/wasm
+RESOURCES += wasmfonts
+
+qtConfig(opengl) {
+ SOURCES += qwasmbackingstore.cpp
+ HEADERS += qwasmbackingstore.h
+}
+CONFIG += egl
+
+OTHER_FILES += \
+ wasm.json \
+ wasm_shell.html \
+ qtloader.js
+
+shell_files.path = $$[QT_INSTALL_PLUGINS]/platforms
+shell_files.files = \
+ wasm_shell.html \
+ qtloader.js \
+ qtlogo.svg
+
+INSTALLS += shell_files
+
+PLUGIN_TYPE = platforms
+PLUGIN_CLASS_NAME = QWasmIntegrationPlugin
+!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
+load(qt_plugin)
diff --git a/src/plugins/platforms/wasm/wasm_shell.html b/src/plugins/platforms/wasm/wasm_shell.html
new file mode 100644
index 0000000000..67bfcdfbdc
--- /dev/null
+++ b/src/plugins/platforms/wasm/wasm_shell.html
@@ -0,0 +1,61 @@
+<!doctype html>
+<html lang="en-us">
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <title>APPNAME</title>
+ <style>
+ html, body { padding: 0; margin : 0; overflow:hidden; height: 100% }
+ /* the canvas *must not* have any border or padding, or mouse coords will be wrong */
+ canvas { border: 0px none; background-color: white; height:100%; width:100%; }
+ </style>
+ </head>
+ <body onload="init()">
+ <figure style="overflow:visible;" id="spinner">
+ <center style="margin-top:1.5em; line-height:150%">
+ <img src="qtlogo.svg"; width=320; height=200; style="display:block"> </img>
+ <strong>Qt for WebAssembly: APPNAME</strong>
+ <div id="status"></div>
+ <noscript>JavaScript is disabled. Please enable JavaScript to use this application.</noscript>
+ </center>
+ </figure>
+ <canvas id="canvas" oncontextmenu="event.preventDefault()"></canvas>
+
+ <script type='text/javascript'>
+ function init() {
+ var spinner = document.getElementById('spinner');
+ var canvas = document.getElementById('canvas');
+ var status = document.getElementById('status')
+
+ var qtLoader = QtLoader({
+ showLoader: function(loaderStatus) {
+ spinner.style.display = 'block';
+ canvas.style.display = 'none';
+ status.innerHTML = loaderStatus + "...";
+ },
+ showError: function(errorText) {
+ status.innerHTML = errorText;
+ spinner.style.display = 'block';
+ canvas.style.display = 'none';
+ },
+ showExit: function() {
+ status.innerHTML = "Application exit";
+ if (qtLoader.exitCode !== undefined)
+ status.innerHTML += " with code " + qtLoader.exitCode;
+ if (qtLoader.exitText !== undefined)
+ status.innerHTML += " (" + qtLoader.exitText + ")";
+ spinner.style.display = 'block';
+ canvas.style.display = 'none';
+ },
+ showCanvas: function() {
+ spinner.style.display = 'none';
+ canvas.style.display = 'block';
+ return canvas;
+ },
+ });
+ qtLoader.loadEmscriptenModule("APPNAME");
+ }
+ </script>
+ <script type="text/javascript" src="qtloader.js"></script>
+ </body>
+</html>
diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h
index ef22a4451a..985f13bdc5 100644
--- a/src/plugins/platforms/windows/qtwindowsglobal.h
+++ b/src/plugins/platforms/windows/qtwindowsglobal.h
@@ -71,6 +71,7 @@
# define WM_POINTERENTER 0x0249
# define WM_POINTERLEAVE 0x024A
# define WM_POINTERACTIVATE 0x024B
+# define WM_POINTERCAPTURECHANGED 0x024C
# define WM_POINTERWHEEL 0x024E
# define WM_POINTERHWHEEL 0x024F
#endif // WM_POINTERUPDATE
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index 0df6264bcb..03bb1bee48 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -65,6 +65,7 @@
#include <QtGui/qwindow.h>
#include <qpa/qwindowsysteminterface.h>
+#include <qpa/qwindowsysteminterface_p.h>
#include <qpa/qplatformnativeinterface.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qopenglcontext.h>
@@ -201,6 +202,7 @@ void QWindowsUser32DLL::init()
getPointerTouchInfo = (GetPointerTouchInfo)library.resolve("GetPointerTouchInfo");
getPointerFrameTouchInfo = (GetPointerFrameTouchInfo)library.resolve("GetPointerFrameTouchInfo");
getPointerPenInfo = (GetPointerPenInfo)library.resolve("GetPointerPenInfo");
+ skipPointerFrameMessages = (SkipPointerFrameMessages)library.resolve("SkipPointerFrameMessages");
}
if (QOperatingSystemVersion::current()
@@ -214,7 +216,8 @@ void QWindowsUser32DLL::init()
bool QWindowsUser32DLL::supportsPointerApi()
{
return enableMouseInPointer && getPointerType && getPointerInfo && getPointerDeviceRects
- && getPointerTouchInfo && getPointerFrameTouchInfo && getPointerPenInfo;
+ && getPointerTouchInfo && getPointerFrameTouchInfo && getPointerPenInfo
+ && skipPointerFrameMessages;
}
void QWindowsShcoreDLL::init()
@@ -327,8 +330,12 @@ bool QWindowsContext::initTouch(unsigned integrationOptions)
if (!touchDevice)
return false;
- if (!(integrationOptions & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch))
- touchDevice->setCapabilities(touchDevice->capabilities() | QTouchDevice::MouseEmulation);
+ if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) {
+ QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
+ } else {
+ if (!(integrationOptions & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch))
+ touchDevice->setCapabilities(touchDevice->capabilities() | QTouchDevice::MouseEmulation);
+ }
QWindowSystemInterface::registerTouchDevice(touchDevice);
diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h
index 33bd42a669..8102e0bf19 100644
--- a/src/plugins/platforms/windows/qwindowscontext.h
+++ b/src/plugins/platforms/windows/qwindowscontext.h
@@ -93,6 +93,7 @@ struct QWindowsUser32DLL
typedef BOOL (WINAPI *GetPointerTouchInfo)(UINT32, PVOID);
typedef BOOL (WINAPI *GetPointerFrameTouchInfo)(UINT32, UINT32 *, PVOID);
typedef BOOL (WINAPI *GetPointerPenInfo)(UINT32, PVOID);
+ typedef BOOL (WINAPI *SkipPointerFrameMessages)(UINT32);
typedef BOOL (WINAPI *SetProcessDPIAware)();
typedef BOOL (WINAPI *AddClipboardFormatListener)(HWND);
typedef BOOL (WINAPI *RemoveClipboardFormatListener)(HWND);
@@ -110,6 +111,7 @@ struct QWindowsUser32DLL
GetPointerTouchInfo getPointerTouchInfo = nullptr;
GetPointerFrameTouchInfo getPointerFrameTouchInfo = nullptr;
GetPointerPenInfo getPointerPenInfo = nullptr;
+ SkipPointerFrameMessages skipPointerFrameMessages = nullptr;
// Windows Vista onwards
SetProcessDPIAware setProcessDPIAware = nullptr;
diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp
index abd4d56da0..d8918d1b3d 100644
--- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp
+++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp
@@ -354,6 +354,17 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
if (count < 1)
return false;
+ if (msg.message == WM_POINTERCAPTURECHANGED) {
+ QWindowSystemInterface::handleTouchCancelEvent(window, m_touchDevice,
+ QWindowsKeyMapper::queryKeyboardModifiers());
+ m_lastTouchPositions.clear();
+ return true;
+ }
+
+ // Only handle down/up/update, ignore others like WM_POINTERENTER, WM_POINTERLEAVE, etc.
+ if (msg.message > WM_POINTERUP)
+ return false;
+
const QScreen *screen = window->screen();
if (!screen)
screen = QGuiApplication::primaryScreen();
@@ -366,7 +377,18 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
QList<QWindowSystemInterface::TouchPoint> touchPoints;
+ if (QWindowsContext::verbose > 1)
+ qCDebug(lcQpaEvents).noquote().nospace() << showbase
+ << __FUNCTION__
+ << " message=" << hex << msg.message
+ << " count=" << dec << count;
+
for (quint32 i = 0; i < count; ++i) {
+ if (QWindowsContext::verbose > 1)
+ qCDebug(lcQpaEvents).noquote().nospace() << showbase
+ << " TouchPoint id=" << touchInfo[i].pointerInfo.pointerId
+ << " frame=" << touchInfo[i].pointerInfo.frameId
+ << " flags=" << hex << touchInfo[i].pointerInfo.pointerFlags;
QWindowSystemInterface::TouchPoint touchPoint;
touchPoint.id = touchInfo[i].pointerInfo.pointerId;
@@ -398,26 +420,14 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition);
}
touchPoints.append(touchPoint);
+
+ // Avoid getting repeated messages for this frame if there are multiple pointerIds
+ QWindowsContext::user32dll.skipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId);
}
QWindowSystemInterface::handleTouchEvent(window, m_touchDevice, touchPoints,
QWindowsKeyMapper::queryKeyboardModifiers());
- if (!(QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch)) {
-
- const QPoint globalPos = QPoint(touchInfo->pointerInfo.ptPixelLocation.x, touchInfo->pointerInfo.ptPixelLocation.y);
- const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos);
- const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
- const Qt::MouseButtons mouseButtons = queryMouseButtons();
-
- QEvent::Type eventType;
- Qt::MouseButton button;
- getMouseEventInfo(msg.message, touchInfo->pointerInfo.ButtonChangeType, globalPos, &eventType, &button);
-
- QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, button, eventType,
- keyModifiers, Qt::MouseEventSynthesizedByQt);
- }
-
return true;
}
@@ -510,15 +520,6 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
QWindowSystemInterface::handleTabletEvent(target, localPos, hiResGlobalPos, device, type, mouseButtons,
pressure, xTilt, yTilt, tangentialPressure, rotation, z,
pointerId, keyModifiers);
-
- if (!(QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch)) {
- QEvent::Type eventType;
- Qt::MouseButton button;
- getMouseEventInfo(msg.message, penInfo->pointerInfo.ButtonChangeType, globalPos, &eventType, &button);
-
- QWindowSystemInterface::handleMouseEvent(target, localPos, globalPos, mouseButtons, button, eventType,
- keyModifiers, Qt::MouseEventSynthesizedByQt);
- }
break;
}
}
diff --git a/src/plugins/printsupport/windows/qwindowsprintdevice.cpp b/src/plugins/printsupport/windows/qwindowsprintdevice.cpp
index 300d553628..071bc01192 100644
--- a/src/plugins/printsupport/windows/qwindowsprintdevice.cpp
+++ b/src/plugins/printsupport/windows/qwindowsprintdevice.cpp
@@ -112,7 +112,7 @@ QWindowsPrintDevice::QWindowsPrintDevice(const QString &id)
{
// First do a fast lookup to see if printer exists, if it does then open it
if (!id.isEmpty() && QWindowsPrintDevice::availablePrintDeviceIds().contains(id)) {
- if (OpenPrinter((LPWSTR)m_id.utf16(), &m_hPrinter, NULL)) {
+ if (OpenPrinter(const_cast<LPWSTR>(wcharId()), &m_hPrinter, nullptr)) {
DWORD needed = 0;
GetPrinter(m_hPrinter, 2, 0, 0, &needed);
QScopedArrayPointer<BYTE> buffer(new BYTE[needed]);
@@ -351,16 +351,19 @@ int QWindowsPrintDevice::defaultResolution() const
void QWindowsPrintDevice::loadInputSlots() const
{
- DWORD binCount = DeviceCapabilities((LPWSTR)m_id.utf16(), NULL, DC_BINS, NULL, NULL);
+ const auto printerId = wcharId();
+ DWORD binCount = DeviceCapabilities(printerId, nullptr, DC_BINS, nullptr, nullptr);
if (int(binCount) > 0
- && DeviceCapabilities((LPWSTR)m_id.utf16(), NULL, DC_BINNAMES, NULL, NULL) == binCount) {
+ && DeviceCapabilities(printerId, nullptr, DC_BINNAMES, nullptr, nullptr) == binCount) {
QScopedArrayPointer<WORD> bins(new WORD[binCount*sizeof(WORD)]);
QScopedArrayPointer<wchar_t> binNames(new wchar_t[binCount*24]);
// Get the details and match the default paper size
- if (DeviceCapabilities((LPWSTR)m_id.utf16(), NULL, DC_BINS, (LPWSTR)bins.data(), NULL) == binCount
- && DeviceCapabilities((LPWSTR)m_id.utf16(), NULL, DC_BINNAMES, binNames.data(), NULL) == binCount) {
+ if (DeviceCapabilities(printerId, nullptr, DC_BINS,
+ reinterpret_cast<LPWSTR>(bins.data()), nullptr) == binCount
+ && DeviceCapabilities(printerId, nullptr, DC_BINNAMES, binNames.data(),
+ nullptr) == binCount) {
for (int i = 0; i < int(binCount); ++i) {
wchar_t *binName = binNames.data() + (i * 24);
@@ -410,7 +413,7 @@ void QWindowsPrintDevice::loadOutputBins() const
void QWindowsPrintDevice::loadDuplexModes() const
{
m_duplexModes.append(QPrint::DuplexNone);
- DWORD duplex = DeviceCapabilities((LPWSTR)m_id.utf16(), NULL, DC_DUPLEX, NULL, NULL);
+ DWORD duplex = DeviceCapabilities(wcharId(), nullptr, DC_DUPLEX, nullptr, nullptr);
if (int(duplex) == 1) {
// TODO Assume if duplex flag supports both modes
m_duplexModes.append(QPrint::DuplexAuto);
@@ -444,7 +447,7 @@ QPrint::DuplexMode QWindowsPrintDevice::defaultDuplexMode() const
void QWindowsPrintDevice::loadColorModes() const
{
m_colorModes.append(QPrint::GrayScale);
- DWORD color = DeviceCapabilities((LPWSTR)m_id.utf16(), NULL, DC_COLORDEVICE, NULL, NULL);
+ DWORD color = DeviceCapabilities(wcharId(), nullptr, DC_COLORDEVICE, nullptr, nullptr);
if (int(color) == 1)
m_colorModes.append(QPrint::Color);
m_haveColorModes = true;
@@ -503,7 +506,7 @@ QString QWindowsPrintDevice::defaultPrintDeviceId()
void QWindowsPrintDevice::loadCopiesSupport() const
{
- LPWSTR printerId = const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(m_id.utf16()));
+ auto printerId = wcharId();
m_supportsMultipleCopies = (DeviceCapabilities(printerId, NULL, DC_COPIES, NULL, NULL) > 1);
m_supportsCollateCopies = DeviceCapabilities(printerId, NULL, DC_COLLATE, NULL, NULL);
m_haveCopies = true;
@@ -552,7 +555,7 @@ void QWindowsPrintDevice::loadMinMaxPageSizes() const
{
// Min/Max custom size is in tenths of a millimeter
const qreal multiplier = qt_pointMultiplier(QPageLayout::Millimeter);
- LPWSTR printerId = const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(m_id.utf16()));
+ auto printerId = wcharId();
DWORD min = DeviceCapabilities(printerId, NULL, DC_MINEXTENT, NULL, NULL);
m_minimumPhysicalPageSize = QSize((LOWORD(min) / 10.0) * multiplier, (HIWORD(min) / 10.0) * multiplier);
DWORD max = DeviceCapabilities(printerId, NULL, DC_MAXEXTENT, NULL, NULL);
diff --git a/src/plugins/printsupport/windows/qwindowsprintdevice.h b/src/plugins/printsupport/windows/qwindowsprintdevice.h
index 9f6d31da5f..166f0f65b2 100644
--- a/src/plugins/printsupport/windows/qwindowsprintdevice.h
+++ b/src/plugins/printsupport/windows/qwindowsprintdevice.h
@@ -140,6 +140,8 @@ protected:
void loadMinMaxPageSizes() const;
private:
+ LPCWSTR wcharId() const { return reinterpret_cast<LPCWSTR>(m_id.utf16()); }
+
HANDLE m_hPrinter;
mutable bool m_haveCopies;
mutable bool m_haveMinMaxPageSizes;
diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm
index dd7959f3cf..c70d1729c0 100644
--- a/src/plugins/styles/mac/qmacstyle_mac.mm
+++ b/src/plugins/styles/mac/qmacstyle_mac.mm
@@ -394,9 +394,9 @@ static bool setupSlider(NSSlider *slider, const QStyleOptionSlider *sl)
const bool ticksAbove = sl->tickPosition == QSlider::TicksAbove;
if (sl->orientation == Qt::Horizontal)
- slider.tickMarkPosition = ticksAbove ? NSTickMarkAbove : NSTickMarkBelow;
+ slider.tickMarkPosition = ticksAbove ? NSTickMarkPositionAbove : NSTickMarkPositionBelow;
else
- slider.tickMarkPosition = ticksAbove ? NSTickMarkLeft : NSTickMarkRight;
+ slider.tickMarkPosition = ticksAbove ? NSTickMarkPositionLeading : NSTickMarkPositionTrailing;
} else {
slider.numberOfTickMarks = 0;
}
@@ -1735,17 +1735,10 @@ NSView *QMacStylePrivate::cocoaControl(CocoaControl widget) const
}
Q_UNREACHABLE();
} ();
-#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_12)
const auto styleMask = NSWindowStyleMaskTitled
| NSWindowStyleMaskClosable
| NSWindowStyleMaskMiniaturizable
| NSWindowStyleMaskResizable;
-#else
- const auto styleMask = NSTitledWindowMask
- | NSClosableWindowMask
- | NSMiniaturizableWindowMask
- | NSResizableWindowMask;
-#endif
bv = [NSWindow standardWindowButton:button forStyleMask:styleMask];
[bv retain];
break;
@@ -1792,10 +1785,10 @@ NSView *QMacStylePrivate::cocoaControl(CocoaControl widget) const
auto *ctrl = static_cast<NSControl *>(bv);
switch (widget.size) {
case QStyleHelper::SizeSmall:
- ctrl.controlSize = NSSmallControlSize;
+ ctrl.controlSize = NSControlSizeSmall;
break;
case QStyleHelper::SizeMini:
- ctrl.controlSize = NSMiniControlSize;
+ ctrl.controlSize = NSControlSizeMini;
break;
default:
break;
@@ -1806,10 +1799,10 @@ NSView *QMacStylePrivate::cocoaControl(CocoaControl widget) const
pi.indeterminate = (widget.type == ProgressIndicator_Indeterminate);
switch (widget.size) {
case QStyleHelper::SizeSmall:
- pi.controlSize = NSSmallControlSize;
+ pi.controlSize = NSControlSizeSmall;
break;
case QStyleHelper::SizeMini:
- pi.controlSize = NSMiniControlSize;
+ pi.controlSize = NSControlSizeMini;
break;
default:
break;
@@ -1855,10 +1848,10 @@ NSCell *QMacStylePrivate::cocoaCell(CocoaControl widget) const
switch (widget.size) {
case QStyleHelper::SizeSmall:
- cell.controlSize = NSSmallControlSize;
+ cell.controlSize = NSControlSizeSmall;
break;
case QStyleHelper::SizeMini:
- cell.controlSize = NSMiniControlSize;
+ cell.controlSize = NSControlSizeMini;
break;
default:
break;
@@ -2198,9 +2191,9 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW
ret = 0;
break;
case PM_TitleBarHeight: {
- NSUInteger style = NSTitledWindowMask;
+ NSUInteger style = NSWindowStyleMaskTitled;
if (widget && ((widget->windowFlags() & Qt::Tool) == Qt::Tool))
- style |= NSUtilityWindowMask;
+ style |= NSWindowStyleMaskUtilityWindow;
ret = int([NSWindow frameRectForContentRect:NSZeroRect
styleMask:style].size.height);
break; }
diff --git a/src/printsupport/kernel/qprintengine_win.cpp b/src/printsupport/kernel/qprintengine_win.cpp
index 5ee93a46b3..e3a5c3d2e8 100644
--- a/src/printsupport/kernel/qprintengine_win.cpp
+++ b/src/printsupport/kernel/qprintengine_win.cpp
@@ -1556,14 +1556,15 @@ HGLOBAL *QWin32PrintEngine::createGlobalDevNames()
Q_D(QWin32PrintEngine);
int size = sizeof(DEVNAMES) + d->m_printDevice.id().length() * 2 + 2;
- HGLOBAL *hGlobal = (HGLOBAL *) GlobalAlloc(GMEM_MOVEABLE, size);
- DEVNAMES *dn = (DEVNAMES*) GlobalLock(hGlobal);
+ auto hGlobal = reinterpret_cast<HGLOBAL *>(GlobalAlloc(GMEM_MOVEABLE, size));
+ auto dn = reinterpret_cast<DEVNAMES*>(GlobalLock(hGlobal));
dn->wDriverOffset = 0;
dn->wDeviceOffset = sizeof(DEVNAMES) / sizeof(wchar_t);
dn->wOutputOffset = 0;
- memcpy((ushort*)dn + dn->wDeviceOffset, d->m_printDevice.id().utf16(), d->m_printDevice.id().length() * 2 + 2);
+ memcpy(reinterpret_cast<ushort*>(dn) + dn->wDeviceOffset,
+ d->m_printDevice.id().utf16(), d->m_printDevice.id().length() * 2 + 2);
dn->wDefault = 0;
GlobalUnlock(hGlobal);
@@ -1574,8 +1575,9 @@ void QWin32PrintEngine::setGlobalDevMode(HGLOBAL globalDevNames, HGLOBAL globalD
{
Q_D(QWin32PrintEngine);
if (globalDevNames) {
- DEVNAMES *dn = (DEVNAMES*) GlobalLock(globalDevNames);
- QString id = QString::fromWCharArray((wchar_t*)(dn) + dn->wDeviceOffset);
+ auto dn = reinterpret_cast<DEVNAMES*>(GlobalLock(globalDevNames));
+ const QString id =
+ QString::fromWCharArray(reinterpret_cast<const wchar_t*>(dn) + dn->wDeviceOffset);
QPlatformPrinterSupport *ps = QPlatformPrinterSupportPlugin::get();
if (ps)
d->m_printDevice = ps->createPrintDevice(id.isEmpty() ? ps->defaultPrintDeviceId() : id);
@@ -1583,7 +1585,7 @@ void QWin32PrintEngine::setGlobalDevMode(HGLOBAL globalDevNames, HGLOBAL globalD
}
if (globalDevMode) {
- DEVMODE *dm = (DEVMODE*) GlobalLock(globalDevMode);
+ auto dm = reinterpret_cast<DEVMODE*>(GlobalLock(globalDevMode));
d->release();
d->globalDevMode = globalDevMode;
if (d->ownsDevMode) {
diff --git a/src/testlib/qappletestlogger.cpp b/src/testlib/qappletestlogger.cpp
index e970f008d2..2c1005ad80 100644
--- a/src/testlib/qappletestlogger.cpp
+++ b/src/testlib/qappletestlogger.cpp
@@ -52,10 +52,7 @@ bool QAppleTestLogger::debugLoggingEnabled()
// Debug-level messages are only captured in memory when debug logging is
// enabled through a configuration change, which can happen automatically
// when running inside Xcode, or with the Console application open.
- if (__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *))
- return os_log_type_enabled(OS_LOG_DEFAULT, OS_LOG_TYPE_DEBUG);
-
- return false;
+ return os_log_type_enabled(OS_LOG_DEFAULT, OS_LOG_TYPE_DEBUG);
}
QAppleTestLogger::QAppleTestLogger(QAbstractTestLogger *logger)
@@ -71,15 +68,13 @@ void QAppleTestLogger::enterTestFunction(const char *function)
// Re-create activity each time
testFunctionActivity = QT_APPLE_LOG_ACTIVITY("Running test function").enter();
- if (__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *)) {
- QTestCharBuffer testIdentifier;
- QTestPrivate::generateTestIdentifier(&testIdentifier);
- QString identifier = QString::fromLatin1(testIdentifier.data());
- QMessageLogContext context(nullptr, 0, nullptr, "qt.test.enter");
- QString message = identifier;
- if (AppleUnifiedLogger::messageHandler(QtDebugMsg, context, message, identifier))
- return; // AUL already printed to stderr
- }
+ QTestCharBuffer testIdentifier;
+ QTestPrivate::generateTestIdentifier(&testIdentifier);
+ QString identifier = QString::fromLatin1(testIdentifier.data());
+ QMessageLogContext context(nullptr, 0, nullptr, "qt.test.enter");
+ QString message = identifier;
+ if (AppleUnifiedLogger::messageHandler(QtDebugMsg, context, message, identifier))
+ return; // AUL already printed to stderr
m_logger->enterTestFunction(function);
}
@@ -113,41 +108,38 @@ static IncidentClassification incidentTypeToClassification(QAbstractTestLogger::
void QAppleTestLogger::addIncident(IncidentTypes type, const char *description,
const char *file, int line)
{
- if (__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *)) {
- IncidentClassification incidentClassification = incidentTypeToClassification(type);
-
- QTestCharBuffer category;
- QTest::qt_asprintf(&category, "qt.test.%s", incidentClassification.second);
- QMessageLogContext context(file, line, /* function = */ nullptr, category.data());
-
- QTestCharBuffer subsystemBuffer;
- // It would be nice to have the data tag as part of the subsystem too, but that
- // will for some tests results in hundreds of thousands of log objects being
- // created, so we limit the subsystem to test functions, which we can hope
- // are reasonably limited.
- generateTestIdentifier(&subsystemBuffer, TestObject | TestFunction);
- QString subsystem = QString::fromLatin1(subsystemBuffer.data());
-
- // We still want the full identifier as part of the message though
- QTestCharBuffer testIdentifier;
- generateTestIdentifier(&testIdentifier);
- QString message = QString::fromLatin1(testIdentifier.data());
- if (qstrlen(description))
- message += QLatin1Char('\n') % QString::fromLatin1(description);
-
- if (AppleUnifiedLogger::messageHandler(incidentClassification.first, context, message, subsystem))
- return; // AUL already printed to stderr
- }
+
+ IncidentClassification incidentClassification = incidentTypeToClassification(type);
+
+ QTestCharBuffer category;
+ QTest::qt_asprintf(&category, "qt.test.%s", incidentClassification.second);
+ QMessageLogContext context(file, line, /* function = */ nullptr, category.data());
+
+ QTestCharBuffer subsystemBuffer;
+ // It would be nice to have the data tag as part of the subsystem too, but that
+ // will for some tests results in hundreds of thousands of log objects being
+ // created, so we limit the subsystem to test functions, which we can hope
+ // are reasonably limited.
+ generateTestIdentifier(&subsystemBuffer, TestObject | TestFunction);
+ QString subsystem = QString::fromLatin1(subsystemBuffer.data());
+
+ // We still want the full identifier as part of the message though
+ QTestCharBuffer testIdentifier;
+ generateTestIdentifier(&testIdentifier);
+ QString message = QString::fromLatin1(testIdentifier.data());
+ if (qstrlen(description))
+ message += QLatin1Char('\n') % QString::fromLatin1(description);
+
+ if (AppleUnifiedLogger::messageHandler(incidentClassification.first, context, message, subsystem))
+ return; // AUL already printed to stderr
m_logger->addIncident(type, description, file, line);
}
void QAppleTestLogger::addMessage(QtMsgType type, const QMessageLogContext &context, const QString &message)
{
- if (__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *)) {
- if (AppleUnifiedLogger::messageHandler(type, context, message))
- return; // AUL already printed to stderr
- }
+ if (AppleUnifiedLogger::messageHandler(type, context, message))
+ return; // AUL already printed to stderr
m_logger->addMessage(type, context, message);
}
diff --git a/src/tools/moc/cbordevice.h b/src/tools/moc/cbordevice.h
new file mode 100644
index 0000000000..25b75b79eb
--- /dev/null
+++ b/src/tools/moc/cbordevice.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Intel Corporation.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CBORDEVICE_H
+#define CBORDEVICE_H
+
+#include <memory>
+#include <stdio.h>
+
+#define CBOR_API inline
+#define CBOR_PRIVATE_API inline
+#define CBOR_NO_PARSER_API 1
+#include <cbor.h>
+
+class CborDevice
+{
+public:
+ CborDevice(FILE *out) : out(out) {}
+
+ void nextItem(const char *comment = nullptr)
+ {
+ i = 0;
+ if (comment)
+ fprintf(out, "\n // %s", comment);
+ }
+
+ static CborError callback(void *self, const void *ptr, size_t len, CborEncoderAppendType t)
+ {
+ auto that = static_cast<CborDevice *>(self);
+ auto data = static_cast<const char *>(ptr);
+ if (t == CborEncoderAppendCborData) {
+ while (len--)
+ that->putByte(*data++);
+ } else {
+ while (len--)
+ that->putChar(*data++);
+ }
+ return CborNoError;
+ }
+
+private:
+ FILE *out;
+ int i = 0;
+
+ void putNewline()
+ {
+ if ((i++ % 8) == 0)
+ fputs("\n ", out);
+ }
+
+ void putByte(uint8_t c)
+ {
+ putNewline();
+ fprintf(out, " 0x%02x, ", c);
+ }
+
+ void putChar(char c)
+ {
+ putNewline();
+ if (c < 0x20 || c >= 0x7f)
+ fprintf(out, " '\\x%x',", uint8_t(c));
+ else if (c == '\'' || c == '\\')
+ fprintf(out, " '\\%c',", c);
+ else
+ fprintf(out, " '%c', ", c);
+ }
+};
+
+#endif // CBORDEVICE_H
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp
index a3ef1147d6..e499d22618 100644
--- a/src/tools/moc/generator.cpp
+++ b/src/tools/moc/generator.cpp
@@ -2,6 +2,7 @@
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com>
+** Copyright (C) 2018 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the tools applications of the Qt Toolkit.
@@ -28,6 +29,7 @@
****************************************************************************/
#include "generator.h"
+#include "cbordevice.h"
#include "outputrevision.h"
#include "utils.h"
#include <QtCore/qmetatype.h>
@@ -36,9 +38,13 @@
#include <QtCore/qjsonvalue.h>
#include <QtCore/qjsonarray.h>
#include <QtCore/qplugin.h>
+#include <QtCore/qstringview.h>
+
+#include <math.h>
#include <stdio.h>
#include <private/qmetaobject_p.h> //for the flags.
+#include <private/qplugin_p.h> //for the flags.
QT_BEGIN_NAMESPACE
@@ -1560,31 +1566,56 @@ void Generator::generateSignal(FunctionDef *def,int index)
fprintf(out, "}\n");
}
-static void writePluginMetaData(FILE *out, const QJsonObject &data)
+static CborError jsonValueToCbor(CborEncoder *parent, const QJsonValue &v);
+static CborError jsonObjectToCbor(CborEncoder *parent, const QJsonObject &o)
{
- const QJsonDocument doc(data);
+ auto it = o.constBegin();
+ auto end = o.constEnd();
+ CborEncoder map;
+ cbor_encoder_create_map(parent, &map, o.size());
+
+ for ( ; it != end; ++it) {
+ QByteArray key = it.key().toUtf8();
+ cbor_encode_text_string(&map, key.constData(), key.size());
+ jsonValueToCbor(&map, it.value());
+ }
+ return cbor_encoder_close_container(parent, &map);
+}
- fputs("\nQT_PLUGIN_METADATA_SECTION\n"
- "static const unsigned char qt_pluginMetaData[] = {\n"
- " 'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', ' ',\n ", out);
-#if 0
- fprintf(out, "\"%s\";\n", doc.toJson().constData());
-#else
- const QByteArray binary = doc.toBinaryData();
- const int last = binary.size() - 1;
- for (int i = 0; i < last; ++i) {
- uchar c = (uchar)binary.at(i);
- if (c < 0x20 || c >= 0x7f)
- fprintf(out, " 0x%02x,", c);
- else if (c == '\'' || c == '\\')
- fprintf(out, " '\\%c',", c);
- else
- fprintf(out, " '%c', ", c);
- if (!((i + 1) % 8))
- fputs("\n ", out);
+static CborError jsonArrayToCbor(CborEncoder *parent, const QJsonArray &a)
+{
+ CborEncoder array;
+ cbor_encoder_create_array(parent, &array, a.size());
+ for (const QJsonValue &v : a)
+ jsonValueToCbor(&array, v);
+ return cbor_encoder_close_container(parent, &array);
+}
+
+static CborError jsonValueToCbor(CborEncoder *parent, const QJsonValue &v)
+{
+ switch (v.type()) {
+ case QJsonValue::Null:
+ case QJsonValue::Undefined:
+ return cbor_encode_null(parent);
+ case QJsonValue::Bool:
+ return cbor_encode_boolean(parent, v.toBool());
+ case QJsonValue::Array:
+ return jsonArrayToCbor(parent, v.toArray());
+ case QJsonValue::Object:
+ return jsonObjectToCbor(parent, v.toObject());
+ case QJsonValue::String: {
+ QByteArray s = v.toString().toUtf8();
+ return cbor_encode_text_string(parent, s.constData(), s.size());
}
- fprintf(out, " 0x%02x\n};\n", (uchar)binary.at(last));
-#endif
+ case QJsonValue::Double: {
+ double d = v.toDouble();
+ if (d == floor(d) && fabs(d) <= (Q_INT64_C(1) << std::numeric_limits<double>::digits))
+ return cbor_encode_int(parent, qint64(d));
+ return cbor_encode_double(parent, d);
+ }
+ }
+ Q_UNREACHABLE();
+ return CborUnknownError;
}
void Generator::generatePluginMetaData()
@@ -1592,32 +1623,48 @@ void Generator::generatePluginMetaData()
if (cdef->pluginData.iid.isEmpty())
return;
- // Write plugin meta data #ifdefed QT_NO_DEBUG with debug=false,
- // true, respectively.
+ fputs("\nQT_PLUGIN_METADATA_SECTION\n"
+ "static constexpr unsigned char qt_pluginMetaData[] = {\n"
+ " 'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', '!',\n"
+ " // metadata version, Qt version, architectural requirements\n"
+ " 0, QT_VERSION_MAJOR, QT_VERSION_MINOR, qPluginArchRequirements(),", out);
- QJsonObject data;
- const QString debugKey = QStringLiteral("debug");
- data.insert(QStringLiteral("IID"), QLatin1String(cdef->pluginData.iid.constData()));
- data.insert(QStringLiteral("className"), QLatin1String(cdef->classname.constData()));
- data.insert(QStringLiteral("version"), (int)QT_VERSION);
- data.insert(debugKey, QJsonValue(false));
- data.insert(QStringLiteral("MetaData"), cdef->pluginData.metaData.object());
- // Add -M args from the command line:
- for (auto it = cdef->pluginData.metaArgs.cbegin(), end = cdef->pluginData.metaArgs.cend(); it != end; ++it)
- data.insert(it.key(), it.value());
+ CborDevice dev(out);
+ CborEncoder enc;
+ cbor_encoder_init_writer(&enc, CborDevice::callback, &dev);
- fputs("\nQT_PLUGIN_METADATA_SECTION const uint qt_section_alignment_dummy = 42;\n\n"
- "#ifdef QT_NO_DEBUG\n", out);
- writePluginMetaData(out, data);
+ CborEncoder map;
+ cbor_encoder_create_map(&enc, &map, CborIndefiniteLength);
- fputs("\n#else // QT_NO_DEBUG\n", out);
+ dev.nextItem("\"IID\"");
+ cbor_encode_int(&map, int(QtPluginMetaDataKeys::IID));
+ cbor_encode_text_string(&map, cdef->pluginData.iid.constData(), cdef->pluginData.iid.size());
- data.remove(debugKey);
- data.insert(debugKey, QJsonValue(true));
- writePluginMetaData(out, data);
+ dev.nextItem("\"className\"");
+ cbor_encode_int(&map, int(QtPluginMetaDataKeys::ClassName));
+ cbor_encode_text_string(&map, cdef->classname.constData(), cdef->classname.size());
- fputs("#endif // QT_NO_DEBUG\n\n", out);
+ QJsonObject o = cdef->pluginData.metaData.object();
+ if (!o.isEmpty()) {
+ dev.nextItem("\"MetaData\"");
+ cbor_encode_int(&map, int(QtPluginMetaDataKeys::MetaData));
+ jsonObjectToCbor(&map, o);
+ }
+
+ // Add -M args from the command line:
+ for (auto it = cdef->pluginData.metaArgs.cbegin(), end = cdef->pluginData.metaArgs.cend(); it != end; ++it) {
+ const QJsonArray &a = it.value();
+ QByteArray key = it.key().toUtf8();
+ dev.nextItem(QByteArray("command-line \"" + key + "\"").constData());
+ cbor_encode_text_string(&map, key.constData(), key.size());
+ jsonArrayToCbor(&map, a);
+ }
+
+ // Close the CBOR map manually
+ dev.nextItem();
+ cbor_encoder_close_container(&enc, &map);
+ fputs("\n};\n", out);
// 'Use' all namespaces.
int pos = cdef->qualified.indexOf("::");
@@ -1627,4 +1674,14 @@ void Generator::generatePluginMetaData()
cdef->qualified.constData(), cdef->classname.constData());
}
+QT_WARNING_DISABLE_GCC("-Wunused-function")
+QT_WARNING_DISABLE_CLANG("-Wunused-function")
+QT_WARNING_DISABLE_CLANG("-Wundefined-internal")
+QT_WARNING_DISABLE_MSVC(4334) // '<<': result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
+
+#define CBOR_ENCODER_WRITER_CONTROL 1
+#define CBOR_ENCODER_WRITE_FUNCTION CborDevice::callback
+
QT_END_NAMESPACE
+
+#include "cborencoder.c"
diff --git a/src/tools/moc/moc.pri b/src/tools/moc/moc.pri
index b689a35478..90839a445b 100644
--- a/src/tools/moc/moc.pri
+++ b/src/tools/moc/moc.pri
@@ -1,5 +1,6 @@
-INCLUDEPATH += $$PWD
+INCLUDEPATH += $$PWD \
+ $$PWD/../../3rdparty/tinycbor/src
HEADERS = $$PWD/moc.h \
$$PWD/preprocessor.h \
@@ -8,7 +9,8 @@ HEADERS = $$PWD/moc.h \
$$PWD/token.h \
$$PWD/utils.h \
$$PWD/generator.h \
- $$PWD/outputrevision.h
+ $$PWD/outputrevision.h \
+ $$PWD/cbordevice.h
SOURCES = $$PWD/moc.cpp \
$$PWD/preprocessor.cpp \
$$PWD/generator.cpp \
diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp
index 9116bf61fe..6b037726a0 100644
--- a/src/widgets/dialogs/qfiledialog.cpp
+++ b/src/widgets/dialogs/qfiledialog.cpp
@@ -1113,7 +1113,7 @@ Q_AUTOTEST_EXPORT QString qt_tildeExpansion(const QString &path)
const QString homePath = QDir::homePath();
#else
const QByteArray userName = path.midRef(1, separatorPosition - 1).toLocal8Bit();
-# if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
+# if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) && !defined(Q_OS_WASM)
passwd pw;
passwd *tmpPw;
char buf[200];
diff --git a/src/widgets/dialogs/qwizard_win.cpp b/src/widgets/dialogs/qwizard_win.cpp
index 5ef304c9f1..aa9ad7f290 100644
--- a/src/widgets/dialogs/qwizard_win.cpp
+++ b/src/widgets/dialogs/qwizard_win.cpp
@@ -606,8 +606,8 @@ bool QVistaHelper::drawTitleText(QPainter *painter, const QString &text, const Q
// Set up the DC
const LOGFONT captionLogFont = getCaptionLogFont(hTheme);
const HFONT hCaptionFont = CreateFontIndirect(&captionLogFont);
- HBITMAP hOldBmp = (HBITMAP)SelectObject(dcMem, (HGDIOBJ) bmp);
- HFONT hOldFont = (HFONT)SelectObject(dcMem, (HGDIOBJ) hCaptionFont);
+ auto hOldBmp = reinterpret_cast<HBITMAP>(SelectObject(dcMem, (HGDIOBJ) bmp));
+ auto hOldFont = reinterpret_cast<HFONT>(SelectObject(dcMem, (HGDIOBJ) hCaptionFont));
// Draw the text!
DTTOPTS dto;
@@ -654,7 +654,7 @@ bool QVistaHelper::drawBlackRect(const QRect &rect, HDC hdc)
dib.bmiHeader.biCompression = BI_RGB;
bmp = CreateDIBSection(hdc, &dib, DIB_RGB_COLORS, NULL, NULL, 0);
- HBITMAP hOldBmp = (HBITMAP)SelectObject(dcMem, (HGDIOBJ) bmp);
+ auto hOldBmp = reinterpret_cast<HBITMAP>(SelectObject(dcMem, (HGDIOBJ) bmp));
BitBlt(hdc, rectDp.left(), rectDp.top(), rectDp.width(), rectDp.height(), dcMem, 0, 0, SRCCOPY);
SelectObject(dcMem, (HGDIOBJ) hOldBmp);
diff --git a/src/widgets/graphicsview/qgraphicsitem_p.h b/src/widgets/graphicsview/qgraphicsitem_p.h
index 9fc6c0794a..d586a22544 100644
--- a/src/widgets/graphicsview/qgraphicsitem_p.h
+++ b/src/widgets/graphicsview/qgraphicsitem_p.h
@@ -500,7 +500,9 @@ public:
quint32 filtersDescendantEvents : 1;
quint32 sceneTransformTranslateOnly : 1;
quint32 notifyBoundingRectChanged : 1;
-
+#ifdef Q_OS_WASM
+ unsigned char :0; //this aligns 64bit field for wasm see QTBUG-65259
+#endif
// New 32 bits
quint32 notifyInvalidated : 1;
quint32 mouseSetsFocus : 1;
diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp
index 51e78ec765..ed0fe0ed91 100644
--- a/src/widgets/kernel/qopenglwidget.cpp
+++ b/src/widgets/kernel/qopenglwidget.cpp
@@ -906,9 +906,19 @@ void QOpenGLWidgetPrivate::invalidateFbo()
const int gl_color_attachment0 = 0x8CE0; // GL_COLOR_ATTACHMENT0
const int gl_depth_attachment = 0x8D00; // GL_DEPTH_ATTACHMENT
const int gl_stencil_attachment = 0x8D20; // GL_STENCIL_ATTACHMENT
+#ifdef Q_OS_WASM
+ // webgl does not allow separate depth and stencil attachments
+ // QTBUG-69913
+ const int gl_depth_stencil_attachment = 0x821A; // GL_DEPTH_STENCIL_ATTACHMENT
+
+ const GLenum attachments[] = {
+ gl_color_attachment0, gl_depth_attachment, gl_stencil_attachment, gl_depth_stencil_attachment
+ };
+#else
const GLenum attachments[] = {
gl_color_attachment0, gl_depth_attachment, gl_stencil_attachment
};
+#endif
f->glDiscardFramebufferEXT(GL_FRAMEBUFFER, sizeof attachments / sizeof *attachments, attachments);
} else {
f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index 23d8d32b0d..4adccceebb 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -6963,8 +6963,10 @@ void QWidget::setTabOrder(QWidget* first, QWidget *second)
determineLastFocusChild(second, lastFocusChildOfSecond);
// If the tab order is already correct, exit early
- if (lastFocusChildOfFirst->d_func()->focus_next == second)
+ if (lastFocusChildOfFirst == second ||
+ lastFocusChildOfFirst->d_func()->focus_next == second) {
return;
+ }
// Note that we need to handle two different sections in the tab chain; The section
// that 'first' belongs to (firstSection), where we are about to insert 'second', and
diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp
index fccc4f33a2..3e55bdaabc 100644
--- a/src/widgets/styles/qstylesheetstyle.cpp
+++ b/src/widgets/styles/qstylesheetstyle.cpp
@@ -4853,13 +4853,12 @@ int QStyleSheetStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, const
return 0;
break;
- case PM_TabBarScrollButtonWidth: {
+ case PM_TabBarScrollButtonWidth:
subRule = renderRule(w, opt, PseudoElement_TabBarScroller);
if (subRule.hasContentsSize()) {
QSize sz = subRule.size();
- return sz.width() != -1 ? sz.width() : sz.height();
+ return (sz.width() != -1 ? sz.width() : sz.height()) / 2;
}
- }
break;
case PM_TabBarTabShiftHorizontal:
@@ -5918,6 +5917,12 @@ QRect QStyleSheetStyle::subElementRect(SubElement se, const QStyleOption *opt, c
}
break;
+ case SE_TabBarScrollLeftButton:
+ case SE_TabBarScrollRightButton:
+ if (hasStyleRule(w, PseudoElement_TabBarScroller))
+ return ParentStyle::subElementRect(se, opt, w);
+ break;
+
case SE_TabBarTearIndicator: {
QRenderRule subRule = renderRule(w, opt, PseudoElement_TabBarTear);
if (subRule.hasContentsSize()) {
diff --git a/tests/auto/corelib/io/qsettings/qsettings.pro b/tests/auto/corelib/io/qsettings/qsettings.pro
index 5b4cc8a691..79552b62df 100644
--- a/tests/auto/corelib/io/qsettings/qsettings.pro
+++ b/tests/auto/corelib/io/qsettings/qsettings.pro
@@ -6,4 +6,6 @@ RESOURCES += qsettings.qrc
INCLUDEPATH += $$PWD/../../kernel/qmetatype
msvc: LIBS += advapi32.lib
+darwin: LIBS += -framework CoreFoundation
+
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
diff --git a/tests/auto/corelib/kernel/qmetatype/qmetatype.pro b/tests/auto/corelib/kernel/qmetatype/qmetatype.pro
index ad148ccc7f..d70befecfd 100644
--- a/tests/auto/corelib/kernel/qmetatype/qmetatype.pro
+++ b/tests/auto/corelib/kernel/qmetatype/qmetatype.pro
@@ -1,6 +1,6 @@
CONFIG += testcase
TARGET = tst_qmetatype
-QT = core testlib
+QT = core-private testlib
INCLUDEPATH += $$PWD/../../../other/qvariant_common
SOURCES = tst_qmetatype.cpp
TESTDATA=./typeFlags.bin
diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp
index 73618db3f4..5d9b5ca95c 100644
--- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp
+++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp
@@ -29,6 +29,7 @@
#include <QtCore>
#include <QtTest/QtTest>
+#include <QtCore/private/qmetaobjectbuilder_p.h>
#include "tst_qmetatype.h"
#include "tst_qvariant_common.h"
@@ -38,6 +39,7 @@
#endif
#include <algorithm>
+#include <memory>
// mingw gcc 4.8 also takes way too long, letting the CI system abort the test
#if defined(__MINGW32__)
@@ -52,12 +54,19 @@ class tst_QMetaType: public QObject
Q_PROPERTY(QList<QVariant> prop READ prop WRITE setProp)
public:
+ struct GadgetPropertyType {
+ QByteArray type;
+ QByteArray name;
+ QVariant testData;
+ };
+
tst_QMetaType() { propList << 42 << "Hello"; }
QList<QVariant> prop() const { return propList; }
void setProp(const QList<QVariant> &list) { propList = list; }
private:
+ void registerGadget(const char * name, const QVector<GadgetPropertyType> &gadgetProperties);
QList<QVariant> propList;
private slots:
@@ -89,6 +98,7 @@ private slots:
void flagsBinaryCompatibility5_0();
void construct_data();
void construct();
+ void typedConstruct();
void constructCopy_data();
void constructCopy();
void typedefs();
@@ -115,6 +125,128 @@ private slots:
void customDebugStream();
};
+struct BaseGenericType
+{
+ int m_typeId = -1;
+ virtual void *constructor(int typeId, void *where, const void *copy) = 0;
+ virtual void staticMetacallFunction(QMetaObject::Call _c, int _id, void **_a) = 0;
+ virtual void saveOperator(QDataStream & out) const = 0;
+ virtual void loadOperator(QDataStream &in) = 0;
+ virtual ~BaseGenericType() {}
+};
+
+struct GenericGadgetType : BaseGenericType
+{
+ void *constructor(int typeId, void *where, const void *copy) override
+ {
+ GenericGadgetType *ret = where ? new(where) GenericGadgetType : new GenericGadgetType;
+ ret->m_typeId = typeId;
+ if (copy) {
+ Q_ASSERT(ret->m_typeId == reinterpret_cast<const GenericGadgetType*>(copy)->m_typeId);
+ *ret = *reinterpret_cast<const GenericGadgetType*>(copy);
+ } else {
+ ret->properties = properties;
+ }
+ return ret;
+ }
+
+ void staticMetacallFunction(QMetaObject::Call _c, int _id, void **_a) override
+ {
+ if (_c == QMetaObject::ReadProperty) {
+ if (_id < properties.size()) {
+ const auto &prop = properties.at(_id);
+ QMetaType::destruct(int(prop.userType()), _a[0]);
+ QMetaType::construct(int(prop.userType()), _a[0], prop.constData());
+ }
+ } else if (_c == QMetaObject::WriteProperty) {
+ if (_id < properties.size()) {
+ auto & prop = properties[_id];
+ prop = QVariant(prop.userType(), _a[0]);
+ }
+ }
+ }
+
+ void saveOperator(QDataStream & out) const override
+ {
+ for (const auto &prop : properties)
+ out << prop;
+ }
+
+ void loadOperator(QDataStream &in) override
+ {
+ for (auto &prop : properties)
+ in >> prop;
+ }
+ QVector<QVariant> properties;
+};
+
+struct GenericPODType : BaseGenericType
+{
+ // BaseGenericType interface
+ void *constructor(int typeId, void *where, const void *copy) override
+ {
+ GenericPODType *ret = where ? new(where) GenericPODType : new GenericPODType;
+ ret->m_typeId = typeId;
+ if (copy) {
+ Q_ASSERT(ret->m_typeId == reinterpret_cast<const GenericPODType*>(copy)->m_typeId);
+ *ret = *reinterpret_cast<const GenericPODType*>(copy);
+ } else {
+ ret->podData = podData;
+ }
+ return ret;
+ }
+
+ void staticMetacallFunction(QMetaObject::Call _c, int _id, void **_a) override
+ {
+ Q_UNUSED(_c);
+ Q_UNUSED(_id);
+ Q_UNUSED(_a);
+ Q_ASSERT(false);
+ }
+
+ void saveOperator(QDataStream &out) const override
+ {
+ out << podData;
+ }
+ void loadOperator(QDataStream &in) override
+ {
+ in >> podData;
+ }
+ QByteArray podData;
+};
+
+using RegisteredType = QPair<std::shared_ptr<BaseGenericType>, std::shared_ptr<QMetaObject>>;
+static QHash<int, RegisteredType> s_managedTypes;
+
+static void GadgetsStaticMetacallFunction(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
+{
+ reinterpret_cast<BaseGenericType*>(_o)->staticMetacallFunction(_c, _id, _a);
+}
+
+static void GadgetTypedDestructor(int typeId, void *ptr)
+{
+ QCOMPARE(typeId, reinterpret_cast<BaseGenericType*>(ptr)->m_typeId);
+ reinterpret_cast<BaseGenericType*>(ptr)->~BaseGenericType();
+}
+
+static void *GadgetTypedConstructor(int type, void *where, const void *copy)
+{
+ auto it = s_managedTypes.find(type);
+ if (it == s_managedTypes.end())
+ return nullptr; // crash the test
+ return it->first->constructor(type, where, copy);
+}
+
+static void GadgetSaveOperator(QDataStream & out, const void *data)
+{
+ reinterpret_cast<const BaseGenericType *>(data)->saveOperator(out);
+}
+
+static void GadgetLoadOperator(QDataStream &in, void *data)
+{
+ reinterpret_cast<BaseGenericType *>(data)->loadOperator(in);
+}
+
struct Foo { int i; };
@@ -149,6 +281,34 @@ class GadgetDerivedAndTyped : public CustomGadget {};
Q_DECLARE_METATYPE(GadgetDerivedAndTyped<int>)
Q_DECLARE_METATYPE(GadgetDerivedAndTyped<int>*)
+void tst_QMetaType::registerGadget(const char *name, const QVector<GadgetPropertyType> &gadgetProperties)
+{
+ QMetaObjectBuilder gadgetBuilder;
+ gadgetBuilder.setClassName(name);
+ QMetaObjectBuilder::MetaObjectFlags metaObjectflags = QMetaObjectBuilder::DynamicMetaObject | QMetaObjectBuilder::PropertyAccessInStaticMetaCall;
+ gadgetBuilder.setFlags(metaObjectflags);
+ auto dynamicGadgetProperties = std::make_shared<GenericGadgetType>();
+ for (const auto &prop : gadgetProperties) {
+ int propertyType = QMetaType::type(prop.type);
+ dynamicGadgetProperties->properties.push_back(QVariant(QVariant::Type(propertyType)));
+ auto dynamicPropery = gadgetBuilder.addProperty(prop.name, prop.type);
+ dynamicPropery.setWritable(true);
+ dynamicPropery.setReadable(true);
+ }
+ auto meta = gadgetBuilder.toMetaObject();
+ meta->d.static_metacall = &GadgetsStaticMetacallFunction;
+ meta->d.superdata = nullptr;
+ const auto flags = QMetaType::WasDeclaredAsMetaType | QMetaType::IsGadget | QMetaType::NeedsConstruction | QMetaType::NeedsDestruction;
+ int gadgetTypeId = QMetaType::registerType(name,
+ &GadgetTypedDestructor,
+ &GadgetTypedConstructor,
+ sizeof(GenericGadgetType),
+ flags, meta);
+ QVERIFY(gadgetTypeId > 0);
+ QMetaType::registerStreamOperators(gadgetTypeId, &GadgetSaveOperator, &GadgetLoadOperator);
+ s_managedTypes[gadgetTypeId] = qMakePair(dynamicGadgetProperties, std::shared_ptr<QMetaObject>{meta, [](QMetaObject *ptr){ ::free(ptr); }});
+}
+
void tst_QMetaType::defined()
{
QCOMPARE(int(QMetaTypeId2<QString>::Defined), 1);
@@ -906,6 +1066,90 @@ FOR_EACH_CORE_METATYPE(RETURN_CONSTRUCT_FUNCTION)
TypeTestFunctionGetter::get(type)();
}
+void tst_QMetaType::typedConstruct()
+{
+ auto testMetaObjectWriteOnGadget = [](QVariant &gadget, const QVector<GadgetPropertyType> &properties)
+ {
+ auto metaObject = QMetaType::metaObjectForType(gadget.userType());
+ QVERIFY(metaObject != nullptr);
+ QCOMPARE(metaObject->methodCount(), 0);
+ QCOMPARE(metaObject->propertyCount(), properties.size());
+ for (int i = 0; i < metaObject->propertyCount(); ++i) {
+ auto prop = metaObject->property(i);
+ QCOMPARE(properties[i].name, prop.name());
+ QCOMPARE(properties[i].type, prop.typeName());
+ prop.writeOnGadget(gadget.data(), properties[i].testData);
+ }
+ };
+
+ auto testMetaObjectReadOnGadget = [](QVariant gadget, const QVector<GadgetPropertyType> &properties)
+ {
+ auto metaObject = QMetaType::metaObjectForType(gadget.userType());
+ QVERIFY(metaObject != nullptr);
+ QCOMPARE(metaObject->methodCount(), 0);
+ QCOMPARE(metaObject->propertyCount(), properties.size());
+ for (int i = 0; i < metaObject->propertyCount(); ++i) {
+ auto prop = metaObject->property(i);
+ QCOMPARE(properties[i].name, prop.name());
+ QCOMPARE(properties[i].type, prop.typeName());
+ if (!QMetaType::typeFlags(prop.userType()).testFlag(QMetaType::IsGadget))
+ QCOMPARE(properties[i].testData, prop.readOnGadget(gadget.constData()));
+ }
+ };
+
+ QVector<GadgetPropertyType> dynamicGadget1 = {
+ {"int", "int_prop", 34526},
+ {"float", "float_prop", 1.23f},
+ {"QString", "string_prop", QString{"Test QString"}}
+ };
+ registerGadget("DynamicGadget1", dynamicGadget1);
+
+ QVariant testGadget1(QVariant::Type(QMetaType::type("DynamicGadget1")));
+ testMetaObjectWriteOnGadget(testGadget1, dynamicGadget1);
+ testMetaObjectReadOnGadget(testGadget1, dynamicGadget1);
+
+
+ QVector<GadgetPropertyType> dynamicGadget2 = {
+ {"int", "int_prop", 512},
+ {"double", "double_prop", 4.56},
+ {"QString", "string_prop", QString{"Another String"}},
+ {"DynamicGadget1", "dynamicGadget1_prop", testGadget1}
+ };
+ registerGadget("DynamicGadget2", dynamicGadget2);
+ QVariant testGadget2(QVariant::Type(QMetaType::type("DynamicGadget2")));
+ testMetaObjectWriteOnGadget(testGadget2, dynamicGadget2);
+ testMetaObjectReadOnGadget(testGadget2, dynamicGadget2);
+ auto g2mo = QMetaType::metaObjectForType(testGadget2.userType());
+ auto dynamicGadget1_prop = g2mo->property(g2mo->indexOfProperty("dynamicGadget1_prop"));
+ testMetaObjectReadOnGadget(dynamicGadget1_prop.readOnGadget(testGadget2.constData()), dynamicGadget1);
+
+
+ // Register POD
+ const QByteArray myPodTesData = "My POD test data";
+ const char podTypeName[] = "DynamicPOD";
+ auto dynamicGadgetProperties = std::make_shared<GenericPODType>();
+ dynamicGadgetProperties->podData = myPodTesData;
+ const auto flags = QMetaType::NeedsConstruction | QMetaType::NeedsDestruction;
+ int podTypeId = QMetaType::registerType(podTypeName,
+ &GadgetTypedDestructor,
+ &GadgetTypedConstructor,
+ sizeof(GenericGadgetType),
+ flags, nullptr);
+ QVERIFY(podTypeId > 0);
+ QMetaType::registerStreamOperators(podTypeId, &GadgetSaveOperator, &GadgetLoadOperator);
+ s_managedTypes[podTypeId] = qMakePair(dynamicGadgetProperties, std::shared_ptr<QMetaObject>{});
+
+ // Test POD
+ QCOMPARE(podTypeId, QMetaType::type(podTypeName));
+ QVariant podVariant{QVariant::Type(podTypeId)};
+ QCOMPARE(myPodTesData, static_cast<const GenericPODType *>(reinterpret_cast<const BaseGenericType *>(podVariant.constData()))->podData);
+
+ QVariant podVariant1{podVariant};
+ podVariant1.detach(); // Test stream operators
+ static_cast<GenericPODType *>(reinterpret_cast<BaseGenericType *>(podVariant.data()))->podData.clear();
+ QCOMPARE(myPodTesData, static_cast<const GenericPODType *>(reinterpret_cast<const BaseGenericType *>(podVariant1.constData()))->podData);
+}
+
template<int ID>
static void testConstructCopyHelper()
{
diff --git a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp
index f004ec7856..927ba49f83 100644
--- a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp
+++ b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp
@@ -456,8 +456,7 @@ void tst_QTimer::moveToThread()
#if defined(Q_OS_WIN32)
QSKIP("Does not work reliably on Windows :(");
#elif defined(Q_OS_MACOS)
- if (__builtin_available(macOS 10.12, *))
- QSKIP("Does not work reliably on macOS 10.12 (QTBUG-59679)");
+ QSKIP("Does not work reliably on macOS 10.12+ (QTBUG-59679)");
#endif
QTimer ti1;
QTimer ti2;
diff --git a/tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp b/tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp
index d285ed79c0..a290c012df 100644
--- a/tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp
+++ b/tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
@@ -30,8 +31,11 @@
#include <QCoreApplication>
#include <QDebug>
#include <QDir>
+#include <qplugin.h>
#include <QPluginLoader>
+#include <private/qplugin_p.h>
+
class tst_QPlugin : public QObject
{
Q_OBJECT
@@ -124,7 +128,10 @@ void tst_QPlugin::scanInvalidPlugin_data()
{
QTest::addColumn<QByteArray>("metadata");
QTest::addColumn<bool>("loads");
+ QTest::addColumn<QString>("errMsg");
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ // Binary JSON metadata
QByteArray prefix = "QTMETADATA ";
{
@@ -138,27 +145,65 @@ void tst_QPlugin::scanInvalidPlugin_data()
obj.insert("debug", true);
#endif
obj.insert("MetaData", QJsonObject());
- QTest::newRow("control") << (prefix + QJsonDocument(obj).toBinaryData()) << true;
+ QTest::newRow("json-control") << (prefix + QJsonDocument(obj).toBinaryData()) << true << "";
}
- QTest::newRow("zeroes") << prefix << false;
+ QTest::newRow("json-zeroes") << prefix << false << " ";
prefix += "qbjs";
- QTest::newRow("bad-json-version0") << prefix << false;
- QTest::newRow("bad-json-version2") << (prefix + QByteArray("\2\0\0\0", 4)) << false;
+ QTest::newRow("bad-json-version0") << prefix << false << " ";
+ QTest::newRow("bad-json-version2") << (prefix + QByteArray("\2\0\0\0", 4)) << false << " ";
// valid qbjs version 1
prefix += QByteArray("\1\0\0\0");
// too large for the file (100 MB)
- QTest::newRow("bad-json-size-large1") << (prefix + QByteArray("\0\0\x40\x06")) << false;
+ QTest::newRow("bad-json-size-large1") << (prefix + QByteArray("\0\0\x40\x06")) << false << " ";
// too large for binary JSON (512 MB)
- QTest::newRow("bad-json-size-large2") << (prefix + QByteArray("\0\0\0\x20")) << false;
+ QTest::newRow("bad-json-size-large2") << (prefix + QByteArray("\0\0\0\x20")) << false << " ";
// could overflow
- QTest::newRow("bad-json-size-large3") << (prefix + "\xff\xff\xff\x7f") << false;
+ QTest::newRow("bad-json-size-large3") << (prefix + "\xff\xff\xff\x7f") << false << " ";
+#endif
+ // CBOR metadata
+ QByteArray cprefix = "QTMETADATA !1234";
+ cprefix[12] = 0; // current version
+ cprefix[13] = QT_VERSION_MAJOR;
+ cprefix[14] = QT_VERSION_MINOR;
+ cprefix[15] = qPluginArchRequirements();
+
+ QByteArray cborValid = [] {
+ QCborMap m;
+ m.insert(int(QtPluginMetaDataKeys::IID), QLatin1String("org.qt-project.tst_qplugin"));
+ m.insert(int(QtPluginMetaDataKeys::ClassName), QLatin1String("tst"));
+ m.insert(int(QtPluginMetaDataKeys::MetaData), QCborMap());
+ return QCborValue(m).toCbor();
+ }();
+ QTest::newRow("cbor-control") << (cprefix + cborValid) << true << "";
+
+ cprefix[12] = 1;
+ QTest::newRow("cbor-major-too-new") << (cprefix + cborValid) << false
+ << " Invalid metadata version";
+
+ cprefix[12] = 0;
+ cprefix[13] = QT_VERSION_MAJOR + 1;
+ QTest::newRow("cbor-major-too-new") << (cprefix + cborValid) << false << "";
+
+ cprefix[13] = QT_VERSION_MAJOR - 1;
+ QTest::newRow("cbor-major-too-old") << (cprefix + cborValid) << false << "";
+
+ cprefix[13] = QT_VERSION_MAJOR;
+ cprefix[14] = QT_VERSION_MINOR + 1;
+ QTest::newRow("cbor-minor-too-new") << (cprefix + cborValid) << false << "";
+
+ QTest::newRow("cbor-invalid") << (cprefix + "\xff") << false
+ << " Metadata parsing error: Invalid CBOR stream: unexpected 'break' byte";
+ QTest::newRow("cbor-not-map1") << (cprefix + "\x01") << false
+ << " Unexpected metadata contents";
+ QTest::newRow("cbor-not-map2") << (cprefix + "\x81\x01") << false
+ << " Unexpected metadata contents";
}
static const char invalidPluginSignature[] = "qplugin testfile";
@@ -214,6 +259,11 @@ void tst_QPlugin::scanInvalidPlugin()
// now try to load this
QFETCH(bool, loads);
+ QFETCH(QString, errMsg);
+ if (!errMsg.isEmpty())
+ QTest::ignoreMessage(QtWarningMsg,
+ "Found invalid metadata in lib " + QFile::encodeName(newName) +
+ ":" + errMsg.toUtf8());
QPluginLoader loader(newName);
QCOMPARE(loader.load(), loads);
if (loads)
diff --git a/tests/auto/corelib/plugin/qplugin/tst_qplugin.pro b/tests/auto/corelib/plugin/qplugin/tst_qplugin.pro
index 8c6540fe87..4432ee20c1 100644
--- a/tests/auto/corelib/plugin/qplugin/tst_qplugin.pro
+++ b/tests/auto/corelib/plugin/qplugin/tst_qplugin.pro
@@ -1,6 +1,6 @@
CONFIG += testcase
TARGET = tst_qplugin
-QT = core testlib
+QT = core-private testlib
SOURCES = tst_qplugin.cpp
TESTDATA += plugins/*
diff --git a/tests/auto/corelib/tools/qmacautoreleasepool/qmacautoreleasepool.pro b/tests/auto/corelib/tools/qmacautoreleasepool/qmacautoreleasepool.pro
index 26b3a47472..8599596344 100644
--- a/tests/auto/corelib/tools/qmacautoreleasepool/qmacautoreleasepool.pro
+++ b/tests/auto/corelib/tools/qmacautoreleasepool/qmacautoreleasepool.pro
@@ -2,3 +2,4 @@ CONFIG += testcase
TARGET = tst_qmacautoreleasepool
QT = core testlib
SOURCES = tst_qmacautoreleasepool.mm
+LIBS += -framework Foundation
diff --git a/tests/auto/gui/image/qimage/qimage.pro b/tests/auto/gui/image/qimage/qimage.pro
index 39fb4d0cc3..b40866892e 100644
--- a/tests/auto/gui/image/qimage/qimage.pro
+++ b/tests/auto/gui/image/qimage/qimage.pro
@@ -8,5 +8,6 @@ qtConfig(c++11): CONFIG += c++11
android:!android-embedded: RESOURCES += qimage.qrc
win32:!winrt: LIBS += -lgdi32 -luser32
+darwin: LIBS += -framework CoreGraphics
TESTDATA += images/*
diff --git a/tests/auto/other/macnativeevents/macnativeevents.pro b/tests/auto/other/macnativeevents/macnativeevents.pro
index 0611377d0b..0fe5949a1d 100644
--- a/tests/auto/other/macnativeevents/macnativeevents.pro
+++ b/tests/auto/other/macnativeevents/macnativeevents.pro
@@ -8,3 +8,5 @@ SOURCES += tst_macnativeevents.cpp
requires(mac)
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
+
+LIBS += -framework AppKit
diff --git a/tests/auto/other/other.pro b/tests/auto/other/other.pro
index fa09e4d03f..61a464356c 100644
--- a/tests/auto/other/other.pro
+++ b/tests/auto/other/other.pro
@@ -7,7 +7,7 @@ SUBDIRS=\
lancelot \
languagechange \
macgui \
- macnativeevents \
+ #macnativeevents \
macplist \
networkselftest \
qaccessibility \
diff --git a/tests/auto/widgets/kernel/qsizepolicy/tst_qsizepolicy.cpp b/tests/auto/widgets/kernel/qsizepolicy/tst_qsizepolicy.cpp
index eb3264be53..89bb946be9 100644
--- a/tests/auto/widgets/kernel/qsizepolicy/tst_qsizepolicy.cpp
+++ b/tests/auto/widgets/kernel/qsizepolicy/tst_qsizepolicy.cpp
@@ -116,8 +116,16 @@ void tst_QSizePolicy::constExpr()
{ Q_CONSTEXPR QSizePolicy sp = QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); Q_UNUSED(sp); }
{ Q_CONSTEXPR QSizePolicy sp = QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding, QSizePolicy::DefaultType);
Q_CONSTEXPR QSizePolicy tp = sp.transposed(); Q_UNUSED(tp); }
- { Q_RELAXED_CONSTEXPR auto sp = QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed, QSizePolicy::CheckBox);
- Q_RELAXED_CONSTEXPR auto tp = sp.transposed(); Q_UNUSED(tp); }
+ {
+ // QTBUG-69983: For ControlType != QSizePolicy::DefaultType, qCountTrailingZeroBits()
+ // is used, which MSVC 15.8.1 does not consider constexpr due to built-ins
+# if defined(QT_HAS_CONSTEXPR_BUILTINS) && (!defined(Q_CC_MSVC) || _MSC_VER < 1915)
+ Q_RELAXED_CONSTEXPR auto sp = QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed, QSizePolicy::CheckBox);
+# else
+ Q_CONSTEXPR auto sp = QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding, QSizePolicy::DefaultType);
+# endif
+ Q_RELAXED_CONSTEXPR auto tp = sp.transposed(); Q_UNUSED(tp);
+ }
#else
QSKIP("QSizePolicy cannot be constexpr with this version of the compiler.");
#endif
diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
index ae50b32164..360e6986f6 100644
--- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
+++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
@@ -188,6 +188,7 @@ private slots:
void reverseTabOrder();
void tabOrderWithProxy();
void tabOrderWithCompoundWidgets();
+ void tabOrderNoChange();
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
void activation();
#endif
@@ -1930,6 +1931,34 @@ void tst_QWidget::tabOrderWithCompoundWidgets()
QVERIFY(lastEdit->hasFocus());
}
+static QVector<QWidget*> getFocusChain(QWidget *start, bool bForward)
+{
+ QVector<QWidget*> ret;
+ QWidget *cur = start;
+ do {
+ ret += cur;
+ auto widgetPrivate = static_cast<QWidgetPrivate *>(qt_widget_private(cur));
+ cur = bForward ? widgetPrivate->focus_next : widgetPrivate->focus_prev;
+ } while (cur != start);
+ return ret;
+}
+
+void tst_QWidget::tabOrderNoChange()
+{
+ QWidget w;
+ auto *verticalLayout = new QVBoxLayout(&w);
+ auto *tabWidget = new QTabWidget(&w);
+ auto *tv = new QTreeView(tabWidget);
+ tabWidget->addTab(tv, QStringLiteral("Tab 1"));
+ verticalLayout->addWidget(tabWidget);
+
+ const auto focusChainForward = getFocusChain(&w, true);
+ const auto focusChainBackward = getFocusChain(&w, false);
+ QWidget::setTabOrder(tabWidget, tv);
+ QCOMPARE(focusChainForward, getFocusChain(&w, true));
+ QCOMPARE(focusChainBackward, getFocusChain(&w, false));
+}
+
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
void tst_QWidget::activation()
{
diff --git a/util/unicode/main.cpp b/util/unicode/main.cpp
index 0f3c28137d..0c3c0b2ee1 100644
--- a/util/unicode/main.cpp
+++ b/util/unicode/main.cpp
@@ -2473,6 +2473,10 @@ static QByteArray createPropertyInfo()
out += ", ";
out += QByteArray::number( p.lowerCaseDiff );
out += ", ";
+ out += "#ifdef Q_OS_WASM \n"
+// " unsigned char : 0; //wasm 64 packing trick QTBUG-65259\n"
+ out += "#endif \n"
+ out += ", ";
// " ushort upperCaseSpecial : 1;\n"
// " signed short upperCaseDiff : 15;\n"
out += QByteArray::number( p.upperCaseSpecial );
@@ -2497,6 +2501,10 @@ static QByteArray createPropertyInfo()
// " ushort nfQuickCheck : 8;\n"
out += QByteArray::number( p.nfQuickCheck );
out += ", ";
+ out += "#ifdef Q_OS_WASM \n"
+// " unsigned char : 0; //wasm 64 packing trick QTBUG-65259\n"
+ out += "#endif \n"
+ out += ", ";
// " ushort graphemeBreakClass : 5; /* 5 used */\n"
// " ushort wordBreakClass : 5; /* 5 used */\n"
// " ushort sentenceBreakClass : 8; /* 4 used */\n"