37 Commits

Author SHA1 Message Date
Morten Sørvig
8e82b16587 wasm: call onExit once and only once on exit
We listen to the onExit and on onAbort Emscripten events,
and also handle exit by exception. Make sure we call
onExit only once on exit, regardless of the order and
number of Emscripten events.

Change-Id: I4833a1056fad0a2706bd6c0f0fce98fb052fe8c8
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
(cherry picked from commit ac4619a36a54a2168ea5d7a2c7d059781564098c)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
2023-12-20 00:44:40 +00:00
Morten Sørvig
e76a04d26c wasm: fix qtloader.js preRun usage
Emscripten documents that preRun should be an array
of functions, but also accepts setting it to a single
function.

qtloader.js was accidentally using this feature, which
works as long as qtloader is the single user, but breaks
if other code expects an array. A typical error in this
case is:

   "Module.preRun.push is not a function"

Fix this by creating and maintaining preRun as an array.

Pick-to: 6.6
Change-Id: Ie1382695f3f25839cb971ab4adc81984fc8c53ca
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
(cherry picked from commit bf39bd8e06e9d66bfb9f01e83c743420e812b630)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
2023-12-14 19:53:01 +00:00
Morten Sørvig
a4d1c30a1b wasm: clarify qtloader onExit behavior
onExit is called whenever the application exits, i.e.
when the app canvas should no longer be displayed and
the loader/embedder code should take some action.

Emscripten provides two callbacks which can be used
here:
  - onExit, called when the app exits (but see EXIT_RUNTIME)
  - onAbort, called on abort errors.

These map to the two cases Qt's onExit supports. onExit
is not called when EXIT_RUNTIME is disabled, which means
we don't need the special case for exit code 0.

In addition call onExit on any exception. The second
call to showUi() in html_shell.html is then not needed
any more and we avoid duplicating the UI state handling
in user code.

Update the qtloader_integration test to handle changes in
behavior (we no longer set the error text on exit). Use
emscripten_force_exit() to simulate application exit -
using this function makes Emscripten call onExit even
when EXIT_RUNTIME is disabled.

Pick-to: 6.6
Change-Id: I72b5463c1836e8d5054e594abbd304fbc67032b7
Reviewed-by: Piotr Wierciński <piotr.wiercinski@qt.io>
Reviewed-by: Mikołaj Boc <Mikolaj.Boc@qt.io>
2023-07-10 05:13:56 +02:00
Morten Sørvig
20d17b1a3b wasm: Add qtloader compatibility API
Implement the main features of the pre Qt 6.6 loader
as adaption layer on top of the new loader.

Pick-to: 6.6
Task-id: QTBUG-115049
Change-Id: Iabe860d3fb0488fd003876508787da3688e0c87b
Reviewed-by: Mikołaj Boc <Mikolaj.Boc@qt.io>
Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
2023-07-10 05:13:46 +02:00
Morten Sørvig
64007c7497 wasm: add "preload" qtloader config property
Add support for downloading files from the web server
to the in-memory file system at application load time.

See included documentation for usage.

This preload functionality is different from Emscripten's
--preload-file and --embed-file in that the files are
not packed to a single data file or embedded in the
JavaScript runtime. Instead, the files are downloaded
individually from the web server, which means that they
can be cached individually, and also updated individually
without rebuilding the application.

Any file type can be preloaded. The primary use case
(at the moment) is preloading Qt plugins and QML imports.

Pick-to: 6.6
Task-number: QTBUG-63925
Change-Id: I2b71b0d6a2c12ecd3ec58e319c679cd3f6b16631
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
2023-07-04 13:42:01 +00:00
Morten Sørvig
d659c93068 wasm: add "qtdir" qtloader config property
This points to the location where qtloader should find
the Qt installation when loading Qt shared libraries
and plugins.

The path is relative to the path of the html file which
contains the application, and is set to "qt" by default.

Deployment of the Qt installation to the web server is
left to the app developer, since this depends on the
exact use case. One possible way to deploy is to create
a "qt" symlink to the Qt installation, for instance:

  html/myapp/myapp.html
  html/myapp/myapp.wasm
  html/myapp/qt -> /path/to/qt

Pick-to: 6.6
Task-number: QTBUG-63925
Change-Id: I76b129dffc75c06ff6bc67d8c20ce12557b32f31
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
2023-07-04 15:42:01 +02:00
Mikolaj Boc
1f6cac0da9 Make WASM export names different across modules
The export name is now ${TARGET_NAME}Entry. This can also be overridden
by using QT_WASM_EXPORT_NAME, both in CMake and qmake

Change-Id: I59c97ae6e22f0b2720716e9d7eff7b6b13d37ab5
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
2023-06-20 09:08:03 +02:00
Morten Sørvig
bc340abe87 wasm: Document (and rename) config.qt.module
This property can take a either a WebAssembly.Module
or a promise to a module, and we don't have to specify
the exact type in the property name.

Pick-to: 6.6
Change-Id: Iebaf52178253afe8c93cf78bbe0853461bf48b67
Reviewed-by: Mikołaj Boc <Mikolaj.Boc@qt.io>
2023-06-20 07:38:41 +02:00
Mikolaj Boc
4230e56d2e Correctly document qtLoad's return value
Documentation got outdated during review of the new qt loader.

Change-Id: I8e23016b9a42e5f003e88c58a8e546255b167983
Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
2023-06-08 18:05:20 +02:00
Mikolaj Boc
b9491daad0 Modernize the qtloader
This is a minimal version of qtloader. The load function accepts
the same arguments as emscripten runtime with a few additions:
- qt.environment
- qt.onExit
- qt.containerElements
- qt.fontDpi
- qt.onLoaded
- qt.entryFunction

State handling has been removed in favor of making the load async
(assume loading when the promise is live).

Public APIs getting crashed status, exit text and code have been
refactored into the new qt.onExit event fed to load. No need for
keeping the state in the loader.

The loader is integration-tested. A test module with test APIs
has been created as a test harness.

The runtime APIs exposed by Qt (font dpi and screen API) are handled
by the qtloader seamlessly.

Change-Id: Iaee65702667da0349a475feae6b83244d966d98d
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
2023-06-05 23:14:28 +02:00
Morten Sørvig
417b61b015 wasm: fix qtloader.js container element regression
As of Qt 6.5 the html document should not create canvas
elements directly, but instead create div container
elements and let Qt create and manage the canvas elements.

However, qtloaders.js has not been updated to match this
and is still creating canvas elements when given div
elements.

Remove the canvas creation code and invert the primary
and fallback case: config.containerElements is now passed
to instance.qtContainerElements. config.canvasElements
is copied to config.containerElements, if set.

Change-Id: I7372db93ee4de5b23a0a5d992597a3fbd9711a33
Pick-to: 6.5 6.5.1
Reviewed-by: Mikołaj Boc <Mikolaj.Boc@qt.io>
2023-05-12 10:15:03 +00:00
Morten Sørvig
8611b9d8be wasm: make qtloader print stack trace on exception
We were displaying the exception type by on the error
page, however the exception contains a stack trace as
well which we can print to the console.

Pick-to: 6.4 6.5
Change-Id: Ia6c95c3f179eb68e57f9d6d2d8ad960591d0b365
Reviewed-by: Aleksandr Reviakin <aleksandr.reviakin@qt.io>
Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
2023-01-09 09:41:26 +00:00
Morten Sørvig
a594e95c9a wasm: support setting Emscripten configuration
Support passing Emscripten configuration options to
the QtLoader constructor using the "moduleConfig"
key.

Previously, it was possible to set Emscripten config options
on the global Module object. However, recent versions
if Qt has switched to using the MODULARIZE=1 build setting,
in which case there is no global object.

Fixes: QTBUG-107979
Pick-to: 6.5
Change-Id: Ie99b772ddbb1d9f5464c868a43c821bae01519e0
Reviewed-by: Mikołaj Boc <Mikolaj.Boc@qt.io>
Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
2023-01-01 23:50:42 +01:00
Mikolaj Boc
626ec74359 Migrate to using the constructor of QtLoader
Wasm shell used to call the function QtLoader instead of constructing
a new QtLoader. Change this.

Also change the doc to recommend using the constructor.

Change-Id: I57c52eab389aa82449c7db3f4c646ffb234df778
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
2022-11-18 18:02:21 +01:00
Mikolaj Boc
2fd4d0586f Call qtUpdateApi on module as expected
The qtUpdateDpi function is a module function, not a scope function
(regardless of it being window-scope self or QtLoader-scope self).
Therefore it should be executed with module as this.

Fixes: QTBUG-108112
Pick-to: 6.4
Change-Id: Ib4604a43dbdd0caa114d3d892ea97b5ee4c9a9a8
Reviewed-by: Aleksandr Reviakin <aleksandr.reviakin@qt.io>
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
2022-11-11 19:31:30 +01:00
Mikolaj Boc
18425c3329 qtLoader: Don't assign properties on random self
The 'const self = this;' declaration was omitted in QtLoader constructor,
which made all of the self.something = value assignments actually
assign to the scope self variable (window.self, in most cases).

Make the loader always be constructed with 'new', and assign 'this' to
'self' to always assign properties to the QtLoader instance.

Change-Id: I9cf7cc95e7341531a702edc431aa242b39911f66
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
2022-11-01 09:28:06 +01:00
Mikolaj Boc
b7802b401f Use the correct module exports in qtloader
Refactoring of module exports in qwasmintegration.cpp was not followed
by adjusting the qtloader. Do this now.

Fixes: QTBUG-105264
Change-Id: Ibb0a4a20c0df1409cdcbba04ebd42c1569ae586a
Reviewed-by: David Skoland <david.skoland@qt.io>
2022-08-03 19:43:35 +02:00
David Skoland
2c66a8a850 Streamline error handling in qtloader.js
Added new function handleError which does the usual work whenever there
there is an error, including logging the error to console. Also make
the app exit when the emscripten module fails to load.

Additionally, make sure we correctly report it as crash
if the module fails to load.

Change-Id: I9d723373a34ccbb146959a2207ebded8bcbd4f18
Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
2022-06-03 05:30:46 +02:00
Lucie Gérard
05fc3aef53 Use SPDX license identifiers
Replace the current license disclaimer in files by
a SPDX-License-Identifier.
Files that have to be modified by hand are modified.
License files are organized under LICENSES directory.

Task-number: QTBUG-67283
Change-Id: Id880c92784c40f3bbde861c0d93f58151c18b9f1
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Reviewed-by: Jörg Bornemann <joerg.bornemann@qt.io>
2022-05-16 16:37:38 +02:00
Morten Sørvig
50b34661fa qtloader.js: remove "getProcAddress" error filtering
Emscripten no longer prints an error for each getProcAddress
lookup failure and this code can be removed.

Change-Id: I082f420772677196c8eb82c49546825c750377ae
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Reviewed-by: David Skoland <david.skoland@qt.io>
2022-05-13 11:15:15 +02:00
Morten Sørvig
a1092b8130 qtloader.js: forward stdErr to console.warn()
This is the correct mapping, and as a bonus the Chrome browser provides
a stack trace on all output from console.warn().

Change-Id: I4a1b95475679d6b54a0690f51c23683514fe7985
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Reviewed-by: David Skoland <david.skoland@qt.io>
2022-05-13 09:15:11 +00:00
Morten Johan Sørvig
4ff5a571b3 wasm: Support non-canvas container elements
Support specifying that Qt should use a div element
as the root container, in which case canvas management
is moved to Qt C++ code.

This enables us to take ownership of the canvas and its
configuration. In addition, it allows creating child
elements for the Qt container (canvas element children
have a special role are as fallback elements displayed
in case the browser can’t show the canvas)

Remove support for reading Module.canvas, which was
deprecated in Qt 5.

Add support for reading Module.qtContainerElements,
which can be either a canvas element (legacy) or a
div element (preferred).

Deprecate qtCanvasElements and print warning on usage.

Change QWasmScreen to accept either a canvas or any
html element. In the latter case, create the canvas
and configure it as required by Qt.

Change-Id: I57df8fb5772b2bfbba081af3f572b8b0e7d51897
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
2022-03-31 18:47:17 +02:00
Morten Johan Sørvig
08ea8aaa8b wasm: don’t exit on clean return from main()
Qt 6 uses Emcripten’s default of not exiting the runtime
when main() exits. Make qtloader not transition to
the “Exited” state when main() exits with code 0, since
this would hide the app canvas.

(The app state tracking code in qtloader is by now
outdated, and should be revisited.)

Pick-to: 6.3
Change-Id: Ib47898f1dd93d87b2675f20cd39f96ac3cb681a7
Reviewed-by: David Skoland <david.skoland@qt.io>
Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
2022-01-05 21:25:49 +01:00
Jonas Kvinge
2675c288e8 wasm: Fix source code comment typos
Change-Id: I9b2b76c01880c7bb515fdc1a6c4ef1f0bcf6be95
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
2021-10-12 15:55:53 +02:00
Morten Johan Sørvig
c6362cd55c wasm: add Emscripten module accessor to qtloader.js
After enabling -s MODULARIZE=1 there is no longer a
global MODULE object. Add module() accessor which can
be used to retrieve the Emscripten module.

This does not really fit with the current state tracking
since the app transitions from “loading” to “running” before
the module object is ready. We’ll have to revisit this
at some point.

Change-Id: Ib7191cf4ce436e1de99f84b63ed4c10936fa62b1
Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
2021-08-27 15:45:24 +02:00
Morten Johan Sørvig
0d0b36a184 wasm: support setting environment again
After enabling -s MODULARIZE=1 there is no longer a
global ENV. Use module.ENV instead.

Change-Id: Ic6958f52c6ceb7014f7f2c78a73f2bce5a43bf41
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
2021-08-19 18:41:53 +02:00
Morten Sørvig
7ee4468a18 wasm: enable MODULARIZE option and set EXPORT_NAME
Make Emscripten generate a global constructor function
("createQtAppInstance()") instead of a global javascript
module object.

This enables more fine-grained control over module
instantiation; previously the module object would be
created when the runtime javascript was evaluated, and
the number of emscripten module/instances was limited
to one per page.

Set EXPORT_NAME to “createQtAppInstance” which avoids
collisions with other non-Qt Emscripten modules on
the same page. A further improvement would be to include
the app name in EXPORT_NAME, but this is not done at
this time.

Update the code in qtloader.js to call the constructor
function instead of working on a global module object.
The qtloader.js API is functional before the wasm and
Emscripten modules have been instantiated; store properties
and forward to the Emscripten module when it's created.

Change-Id: I12c49a5b9a4a932bbc46fcc5e5ecc453fd0fe7f0
Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
2021-06-22 11:11:20 +00:00
Avindra Goolcharan
1ee2558b23 wasm/js: fix invalid restartCount reference
The `restartCount` variable on line 245 is mutating
global scope. The PR makes it consistent with the
rest ob the code (`self.restartCount`).

It was observed when importing the qtloader in a
typical Webpack/Babel build environment.

Change-Id: I338285f4f6bcb80df0c16d80cc3ebfec944a8be7
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
2020-12-08 01:56:22 -05:00
Morten Johan Sørvig
56acf089c7 wasm: support setting the font DPI from JS
We have not really been able to determine what the
default DPI should be, so make it configurable with
API on qtloader.js:

  qtLoader.setFontDpi(72);

Also lowers the default DPI to the standard value of
96 (down from Qt default 100).

Task-number: QTBUG-75510
Change-Id: Ica1164c8d80bb06519233adebf2c9e400c0991ce
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
2019-05-13 12:29:21 +00:00
Lorn Potter
837c80bad3 wasm: fix passing environmental variables
Task-number: QTBUG-75530
Change-Id: Ic0f0bd8ce863f55d737d96bbf9e5473466381c9b
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
2019-05-06 09:49:38 +00:00
Morten Johan Sørvig
7bae1bd5cb wasm: hide canvas text caret
Another side effect of setting contenteditable on the
canvas. Seen on Firefox.

Change-Id: I789ba4d7e6fbbdbf14b66fe1ae57183ec04e04bb
Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
2019-04-04 09:29:50 +00:00
Morten Johan Sørvig
69beb5f5a0 wasm: add resizeCanvasElement() API to qtloader.js
HTMl does not have per-element resize events, which
means Qt has not way of knowing that a canvas has been
resized and that the canvas buffer size should be updated.

Depending on the use case, the hosting JavaScript code
that caused the canvas resize could also inform Qt
that the canvas has been resized. Add API to do this,
which calls the existing canvas/screen resize implementation.

Other solutions taken/not taken:

- browser window resize events: these are available,
and we install an event handler in qwasmeventtranslator.cpp.

- DOM mutation events: would detect changes to the
the size attributes themselves, but not if the size
indirectly changed, e.g. “width: 100%” depends on the
parent width. Not implemented.

Change-Id: Ib324bb30f523e9fceea68000b95bf857a1d36b6c
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
2019-04-01 07:18:05 +00:00
Morten Johan Sørvig
73db765aaf wasm: support adding and removing canvases at runtime
Add qtloader API:
  addCanvasElement()
  removeCanvasElement()

These functions call the corresponding add/remove screen
functions on QWasmIntegration.

Task-number: QTBUG-64079
Change-Id: I537c11f3b5fb9240cca9b6313dd45f803d865ac6
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
2019-04-01 07:17:58 +00:00
Morten Johan Sørvig
caa74f16d4 wasm: support rendering to multiple canvases
Qt (via the the qtloader.js API) now supports rendering
to multiple canvases. The application sees each canvas
as a QScreen.

Make qtloader.js support multiple canvases:

  var qtloader = QtLoader({
    canvasElements : [array-of-canvas],
    showCanvas: function() {
      // make canvas(es) visible
    },
 });

The canvases were previously created/returned by showCanvas(),
however this function is called after the Qt app has
been started and adding screens that that point is
too late. (This worked before since there was only one
screen, and no need to connect each screen instance
to specific canvas.)

Remove QWasmScreen, QWasmCompositor, and QWasmEventTranslator
singletons from QWasmIntegration. These are are now
crated per-screen and are owned by the QWasmScreen.

Task-number: QTBUG-64079
Change-Id: I24689929fd5bfb7ff0ba076f66937728fa4bc4e4
Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
2019-03-08 10:09:57 +00:00
Morten Johan Sørvig
070f75d3b0 wasm: improve clipboard fallback path
This improves handling of cut/copy/paste clipboard events,
ands allows clipboard access via the common keyboard
shortcuts.

Make the canvas be eligible for clipboard events by
setting the contenteditable attribute. Install clipboard
event handlers directly on the canvas.

Suppress Ctrl+X/C/V key event handling in the keyboard
event handler in order to make the browser generate
clipboard events. Send synthetic key events from the
clipboard event handlers to make the app copy/paste
to Qt’s clipboard at the correct time.

Access the system clipboard data using event.clipboardData.

Task-number: QTBUG-64638
Change-Id: I584b78ffa2b755b1b76e477b970255c6e5522f6a
Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
2019-03-04 08:21:28 +00:00
Morten Johan Sørvig
de4f256d48 Wasm: enable thread support
configure.json: Make the “thread” feature be allowed
for wasm but disabled by default.

Change qmake.conf and wasm.prf to enable Emscripten
pthreads mode:
- Add USE_PTHREADS=1 linker flag
- Add PTHREAD_POOL_SIZE linker flag with a default pool size (4).
- Add TOTAL_MEMORY linker flag to set available memory (1GB)

It is possible to override options such as PTHREAD_POOL_SIZE
from the application .pro file using QMAKE_WASM_PTHREAD_POOL_SIZE
To change TOTAL_MEMORY, use QMAKE_WASM_TOTAL_MEMORY

Make qtloader.js work in pthreads mode:
- The Module.instantiateWasm callback must provide the module
  in addition to the instance to Emscripten.
- Set Module.mainScriptUrlOrBlob so that the pthreads web workers
  can access the main script

Task-number: QTBUG-64625
Change-Id: I1ab5a559ec97c27c5fc24500ba5f863bcd275141
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
2019-02-07 16:13:26 +00:00
Morten Johan Sørvig
29c0377f07 WebAssembly for QtBase
This is the squashed diff from wip/webassembly to dev.

Done-with: Peng Wu <peng.wu@intopalo.com>
Done-with: Sami Enne <sami.enne@intopalo.com>
Done-with: Morten Johan Sørvig <morten.sorvig@qt.io>
Started-by: Andrew Knight <andrew.knight@intopalo.com>
Change-Id: I6562433c0a38d6ec49ab675e0f104f2665f3392d
Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
2018-08-30 06:48:33 +00:00