From 387f120bf9d6c718796efe5d0db772abc71ab442 Mon Sep 17 00:00:00 2001 From: Yuhang Zhao <2546789017@qq.com> Date: Sat, 30 Mar 2019 13:52:48 +0800 Subject: [PATCH 01/17] Fix cross compile on Ubuntu When cross compiling on Ubuntu with LTO enabled, the linker will complain about the "-fno-fat-objects" parameter even if the "-fuse-linker-plugin" is passed it. But if the "-fno-fat-objects" parameter is removed, the linker will complain about "don't support linker plugin in this mode". Remove both parameters can fix this. Change-Id: I2d792ca70737f2e82a360bfc597f2b110513b954 Reviewed-by: Thiago Macieira --- mkspecs/win32-g++/qmake.conf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mkspecs/win32-g++/qmake.conf b/mkspecs/win32-g++/qmake.conf index ed131c6823..5e9923357f 100644 --- a/mkspecs/win32-g++/qmake.conf +++ b/mkspecs/win32-g++/qmake.conf @@ -22,4 +22,8 @@ QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON QMAKE_LINK = $${CROSS_COMPILE}g++ QMAKE_LINK_C = $${CROSS_COMPILE}gcc +QMAKE_CFLAGS_LTCG = -flto +QMAKE_CXXFLAGS_LTCG = $$QMAKE_CFLAGS_LTCG +QMAKE_LFLAGS_LTCG = $$QMAKE_CFLAGS_LTCG + load(qt_config) From 28a264cfe2d161f2eba3b1efa3ea4985445cd2de Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 8 Mar 2019 10:55:14 +0100 Subject: [PATCH 02/17] Fix alpha blending regression with WA_StacksOnTop QOpenGLWidgets 0bc42886898 in Qt 5.6 introduced support for premultiplied alpha in the raster-rendered QWidget content. Unfortunately this introduced a regression for OpenGL content from QOpenGLWidgets with WA_StacksOnTop set: these used standard alpha blending in 5.5 and earlier, and switching them to premultiplied (in case the - unrelated - raster content has a _Premultiplied QImage format) breaks all content that was done with non-premultiplied alpha in mind, for example the qopenglwidget example's "Transparent background" checkbox. Restore the pre-5.6 behavior. Fixes: QTBUG-74285 Change-Id: I76fcadd53cd436efa2b619b8d6739270995d044f Reviewed-by: Allan Sandfeld Jensen --- src/gui/painting/qplatformbackingstore.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp index afb4613ba5..c71d82546a 100644 --- a/src/gui/painting/qplatformbackingstore.cpp +++ b/src/gui/painting/qplatformbackingstore.cpp @@ -446,6 +446,11 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i d_ptr->blitter->setRedBlueSwizzle(false); } + // There is no way to tell if the OpenGL-rendered content is premultiplied or not. + // For compatibility, assume that it is not, and use normal alpha blend always. + if (d_ptr->premultiplied) + funcs->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + // Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set. for (int i = 0; i < textures->count(); ++i) { if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) From ed49a84e6caa8c76f2edd382a4405028d07a9fba Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Wed, 27 Mar 2019 18:45:10 +0100 Subject: [PATCH 03/17] QListWidget: don't hide setBackgroundColor with QT_DISABLE_DEPRECATED_SINCE QListWidget::setBackgroundColor() is a virtual function. Hiding this function when compiling/linking against QtWidgets when QT_DISABLE_DEPRECATED_SINCE is set will therefore screw up the vtable and it will crash on runtime. Therefore don't surround them with QT_DEPRECATED_SINCE macro. Fixes: QTBUG-74665 Change-Id: Icb0f253117a1e55a338d2d6969ec2d59fbd0679d Reviewed-by: Giuseppe D'Angelo Reviewed-by: David Faure --- src/widgets/itemviews/qlistwidget.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/widgets/itemviews/qlistwidget.h b/src/widgets/itemviews/qlistwidget.h index c093d13e6d..c102b144df 100644 --- a/src/widgets/itemviews/qlistwidget.h +++ b/src/widgets/itemviews/qlistwidget.h @@ -118,10 +118,11 @@ public: QT_DEPRECATED_X ("Use QListWidgetItem::background() instead") inline QColor backgroundColor() const { return qvariant_cast(data(Qt::BackgroundRole)); } +#endif + // no QT_DEPRECATED_SINCE because it is a virtual function QT_DEPRECATED_X ("Use QListWidgetItem::setBackground() instead") virtual void setBackgroundColor(const QColor &color) { setData(Qt::BackgroundRole, color); } -#endif inline QBrush background() const { return qvariant_cast(data(Qt::BackgroundRole)); } From 3cdf46059a668f588fe237aa881c300dd76cbf9e Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 27 Mar 2019 13:38:05 +0100 Subject: [PATCH 04/17] Let "qmake -install qinstall" set default permissions 0644 and 0755 ...like the install commands before Qt 5.9 did. This ensures consistent permissions. Also, we can throw away the code that took care of removing and re-adding the read-only flag on Windows. Change-Id: I06bc3af8817f18c016119fbcb7360800d6c129bd Fixes: QTBUG-74733 Reviewed-by: Simon Hausmann --- qmake/main.cpp | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/qmake/main.cpp b/qmake/main.cpp index a4ef79227b..e5f7032554 100644 --- a/qmake/main.cpp +++ b/qmake/main.cpp @@ -260,31 +260,25 @@ static int installFile(const QString &source, const QString &target, bool exe = return 3; } + QFileDevice::Permissions targetPermissions = QFileDevice::ReadOwner | QFileDevice::WriteOwner + | QFileDevice::ReadUser | QFileDevice::WriteUser + | QFileDevice::ReadGroup | QFileDevice::ReadOther; if (exe) { - if (!targetFile.setPermissions(sourceFile.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeUser | - QFileDevice::ExeGroup | QFileDevice::ExeOther)) { - fprintf(stderr, "Error setting execute permissions on %s: %s\n", - qPrintable(target), qPrintable(targetFile.errorString())); - return 3; - } + targetPermissions |= QFileDevice::ExeOwner | QFileDevice::ExeUser | + QFileDevice::ExeGroup | QFileDevice::ExeOther; + } + if (!targetFile.setPermissions(targetPermissions)) { + fprintf(stderr, "Error setting permissions on %s: %s\n", + qPrintable(target), qPrintable(targetFile.errorString())); + return 3; } // Copy file times QString error; -#ifdef Q_OS_WIN - const QFile::Permissions permissions = targetFile.permissions(); - const bool readOnly = !(permissions & QFile::WriteUser); - if (readOnly) - targetFile.setPermissions(permissions | QFile::WriteUser); -#endif if (!IoUtils::touchFile(target, sourceFile.fileName(), &error)) { fprintf(stderr, "%s", qPrintable(error)); return 3; } -#ifdef Q_OS_WIN - if (readOnly) - targetFile.setPermissions(permissions); -#endif return 0; } From 9e97d64ccd27adcb2053c90cfbcafaef68e53893 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Tue, 12 Mar 2019 11:59:58 +0100 Subject: [PATCH 05/17] Fix installation of .pdb files for applications that have VERSION set For applications that set VERSION the installation targets of pdb files were wrong in qmake's nmake Makefile generator. Replace code that tries to reconstruct that target's versioned extension with TARGET_EXT which already contains the fully resolved target extension. Fixes: QTBUG-74265 Change-Id: I9553a5f70170e077a59c866079ae51647ae80bef Reviewed-by: Oliver Wolff --- qmake/generators/win32/msvc_nmake.cpp | 19 +++++++++++-------- tests/auto/tools/qmake/tst_qmake.cpp | 5 +---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp index 650c0888c7..f295705e2e 100644 --- a/qmake/generators/win32/msvc_nmake.cpp +++ b/qmake/generators/win32/msvc_nmake.cpp @@ -95,7 +95,9 @@ QString NmakeMakefileGenerator::defaultInstall(const QString &t) if (project->isActiveConfig("debug_info")) { if (t == "dlltarget" || project->values(ProKey(t + ".CONFIG")).indexOf("no_dll") == -1) { - QString pdb_target = project->first("TARGET") + project->first("TARGET_VERSION_EXT") + ".pdb"; + const QFileInfo targetFileInfo = project->first("DESTDIR") + project->first("TARGET") + + project->first("TARGET_EXT"); + const QString pdb_target = targetFileInfo.completeBaseName() + ".pdb"; QString src_targ = (project->isEmpty("DESTDIR") ? QString("$(DESTDIR)") : project->first("DESTDIR")) + pdb_target; QString dst_targ = filePrefixRoot(root, fileFixify(targetdir + pdb_target, FileFixifyAbsolute)); if(!ret.isEmpty()) @@ -252,15 +254,16 @@ void NmakeMakefileGenerator::init() project->values("PRECOMPILED_PCH_C") = ProStringList(precompPchC); } - ProString tgt = project->first("DESTDIR") - + project->first("TARGET") + project->first("TARGET_VERSION_EXT"); + const QFileInfo targetFileInfo = project->first("DESTDIR") + project->first("TARGET") + + project->first("TARGET_EXT"); + const ProString targetBase = targetFileInfo.path() + '/' + targetFileInfo.completeBaseName(); if (project->first("TEMPLATE") == "lib" && project->isActiveConfig("shared")) { - project->values("QMAKE_CLEAN").append(tgt + ".exp"); - project->values("QMAKE_DISTCLEAN").append(tgt + ".lib"); + project->values("QMAKE_CLEAN").append(targetBase + ".exp"); + project->values("QMAKE_DISTCLEAN").append(targetBase + ".lib"); } if (project->isActiveConfig("debug_info")) { QString pdbfile; - QString distPdbFile = tgt + ".pdb"; + QString distPdbFile = targetBase + ".pdb"; if (project->isActiveConfig("staticlib")) { // For static libraries, the compiler's pdb file and the dist pdb file are the same. pdbfile = distPdbFile; @@ -276,8 +279,8 @@ void NmakeMakefileGenerator::init() project->values("QMAKE_DISTCLEAN").append(distPdbFile); } if (project->isActiveConfig("debug")) { - project->values("QMAKE_CLEAN").append(tgt + ".ilk"); - project->values("QMAKE_CLEAN").append(tgt + ".idb"); + project->values("QMAKE_CLEAN").append(targetBase + ".ilk"); + project->values("QMAKE_CLEAN").append(targetBase + ".idb"); } else { ProStringList &defines = project->values("DEFINES"); if (!defines.contains("NDEBUG")) diff --git a/tests/auto/tools/qmake/tst_qmake.cpp b/tests/auto/tools/qmake/tst_qmake.cpp index 1eaf66311c..cacee30c86 100644 --- a/tests/auto/tools/qmake/tst_qmake.cpp +++ b/tests/auto/tools/qmake/tst_qmake.cpp @@ -244,7 +244,6 @@ void tst_qmake::simple_app_versioned() QVERIFY2(QFile::exists(pdbFilePath), qPrintable(pdbFilePath)); QVERIFY(test_compiler.make(buildDir, "install")); QString installedPdbFilePath = installDir + '/' + targetBase + ".pdb"; - QEXPECT_FAIL("", "QTBUG-74265", Continue); QVERIFY2(QFile::exists(installedPdbFilePath), qPrintable(installedPdbFilePath)); } @@ -252,10 +251,8 @@ void tst_qmake::simple_app_versioned() QVERIFY(test_compiler.exists(destDir, "simple app", Exe, version)); QVERIFY(test_compiler.makeDistClean(buildDir)); QVERIFY(!test_compiler.exists(destDir, "simple app", Exe, version)); - if (checkPdb) { - QEXPECT_FAIL("", "QTBUG-74265", Continue); + if (checkPdb) QVERIFY(!QFile::exists(pdbFilePath)); - } QVERIFY(test_compiler.removeMakefile(buildDir)); } From 73db765aaf9fad622f050e55e1d240329da0a07c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Fri, 15 Mar 2019 19:42:17 +0100 Subject: [PATCH 06/17] wasm: support adding and removing canvases at runtime MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/plugins/platforms/wasm/qtloader.js | 20 ++++++++++++ .../platforms/wasm/qwasmintegration.cpp | 31 ++++++++++++++----- src/plugins/platforms/wasm/qwasmintegration.h | 7 ++--- 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/plugins/platforms/wasm/qtloader.js b/src/plugins/platforms/wasm/qtloader.js index 049eb1c35e..9bacce5944 100644 --- a/src/plugins/platforms/wasm/qtloader.js +++ b/src/plugins/platforms/wasm/qtloader.js @@ -118,6 +118,10 @@ // "Exited", iff crashed is false. // exitText // Abort/exit message. +// addCanvasElement +// Add canvas at run-time. Adds a corresponding QScreen, +// removeCanvasElement +// Remove canvas at run-time. Removes the corresponding QScreen. var Module = {} @@ -227,6 +231,8 @@ function QtLoader(config) publicAPI.canLoadApplication = canLoadQt(); publicAPI.status = undefined; publicAPI.loadEmscriptenModule = loadEmscriptenModule; + publicAPI.addCanvasElement = addCanvasElement; + publicAPI.removeCanvasElement = removeCanvasElement; restartCount = 0; @@ -528,6 +534,20 @@ function QtLoader(config) window.setTimeout(function() { handleStatusChange(); }, 0); } + function addCanvasElement(element) { + if (publicAPI.status == "Running") + Module.qtAddCanvasElement(element); + else + console.log("Error: addCanvasElement can only be called in the Running state"); + } + + function removeCanvasElement(element) { + if (publicAPI.status == "Running") + Module.qtRemoveCanvasElement(element); + else + console.log("Error: removeCanvasElement can only be called in the Running state"); + } + setStatus("Created"); return publicAPI; diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp index 3b4800a787..44b4546dc6 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.cpp +++ b/src/plugins/platforms/wasm/qwasmintegration.cpp @@ -61,9 +61,23 @@ static void browserBeforeUnload(emscripten::val) QWasmIntegration::QWasmBrowserExit(); } +static void addCanvasElement(emscripten::val canvas) +{ + QString canvasId = QString::fromStdString(canvas["id"].as()); + QWasmIntegration::get()->addScreen(canvasId); +} + +static void removeCanvasElement(emscripten::val canvas) +{ + QString canvasId = QString::fromStdString(canvas["id"].as()); + QWasmIntegration::get()->removeScreen(canvasId); +} + EMSCRIPTEN_BINDINGS(qtQWasmIntegraton) { function("qtBrowserBeforeUnload", &browserBeforeUnload); + function("qtAddCanvasElement", &addCanvasElement); + function("qtRemoveCanvasElement", &removeCanvasElement); } QWasmIntegration *QWasmIntegration::s_instance; @@ -99,8 +113,9 @@ QWasmIntegration::~QWasmIntegration() { delete m_fontDb; - while (!m_screens.isEmpty()) - QWindowSystemInterface::handleScreenRemoved(m_screens.takeLast()); + for (auto it = m_screens.constBegin(); it != m_screens.constEnd(); ++it) + QWindowSystemInterface::handleScreenRemoved(*it); + m_screens.clear(); s_instance = nullptr; } @@ -184,17 +199,17 @@ QPlatformClipboard* QWasmIntegration::clipboard() const return m_clipboard; } -QVector QWasmIntegration::screens() -{ - return m_screens; -} - void QWasmIntegration::addScreen(const QString &canvasId) { QWasmScreen *screen = new QWasmScreen(canvasId); m_clipboard->installEventHandlers(canvasId); - m_screens.append(screen); + m_screens.insert(canvasId, screen); QWindowSystemInterface::handleScreenAdded(screen); } +void QWasmIntegration::removeScreen(const QString &canvasId) +{ + QWindowSystemInterface::handleScreenRemoved(m_screens.take(canvasId)); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h index 5c0ac0b297..01ce6ec007 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.h +++ b/src/plugins/platforms/wasm/qwasmintegration.h @@ -70,21 +70,20 @@ public: QStringList themeNames() const override; QPlatformTheme *createPlatformTheme(const QString &name) const override; QPlatformClipboard *clipboard() const override; - - QVectorscreens(); QWasmClipboard *getWasmClipboard() { return m_clipboard; } static QWasmIntegration *get() { return s_instance; } static void QWasmBrowserExit(); -private: void addScreen(const QString &canvasId); + void removeScreen(const QString &canvasId); +private: mutable QWasmFontDatabase *m_fontDb; mutable QWasmEventDispatcher *m_eventDispatcher; mutable QHash m_backingStores; - QVector m_screens; + QHash m_screens; mutable QWasmClipboard *m_clipboard; static QWasmIntegration *s_instance; }; From 69beb5f5a04bbb5b7fd64e69d1a655c0f5d956cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Sat, 16 Mar 2019 23:58:36 +0100 Subject: [PATCH 07/17] wasm: add resizeCanvasElement() API to qtloader.js MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/plugins/platforms/wasm/qtloader.js | 8 ++++++++ src/plugins/platforms/wasm/qwasmintegration.cpp | 12 ++++++++++++ src/plugins/platforms/wasm/qwasmintegration.h | 1 + 3 files changed, 21 insertions(+) diff --git a/src/plugins/platforms/wasm/qtloader.js b/src/plugins/platforms/wasm/qtloader.js index 9bacce5944..3cbb1c8aa8 100644 --- a/src/plugins/platforms/wasm/qtloader.js +++ b/src/plugins/platforms/wasm/qtloader.js @@ -122,6 +122,8 @@ // Add canvas at run-time. Adds a corresponding QScreen, // removeCanvasElement // Remove canvas at run-time. Removes the corresponding QScreen. +// resizeCanvasElement +// Signals to the application that a canvas has been resized. var Module = {} @@ -233,6 +235,7 @@ function QtLoader(config) publicAPI.loadEmscriptenModule = loadEmscriptenModule; publicAPI.addCanvasElement = addCanvasElement; publicAPI.removeCanvasElement = removeCanvasElement; + publicAPI.resizeCanvasElement = resizeCanvasElement; restartCount = 0; @@ -548,6 +551,11 @@ function QtLoader(config) console.log("Error: removeCanvasElement can only be called in the Running state"); } + function resizeCanvasElement(element) { + if (publicAPI.status == "Running") + Module.qtResizeCanvasElement(element); + } + setStatus("Created"); return publicAPI; diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp index 44b4546dc6..55bb167fcc 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.cpp +++ b/src/plugins/platforms/wasm/qwasmintegration.cpp @@ -73,11 +73,18 @@ static void removeCanvasElement(emscripten::val canvas) QWasmIntegration::get()->removeScreen(canvasId); } +static void resizeCanvasElement(emscripten::val canvas) +{ + QString canvasId = QString::fromStdString(canvas["id"].as()); + QWasmIntegration::get()->resizeScreen(canvasId); +} + EMSCRIPTEN_BINDINGS(qtQWasmIntegraton) { function("qtBrowserBeforeUnload", &browserBeforeUnload); function("qtAddCanvasElement", &addCanvasElement); function("qtRemoveCanvasElement", &removeCanvasElement); + function("qtResizeCanvasElement", &resizeCanvasElement); } QWasmIntegration *QWasmIntegration::s_instance; @@ -212,4 +219,9 @@ void QWasmIntegration::removeScreen(const QString &canvasId) QWindowSystemInterface::handleScreenRemoved(m_screens.take(canvasId)); } +void QWasmIntegration::resizeScreen(const QString &canvasId) +{ + m_screens.value(canvasId)->updateQScreenAndCanvasRenderSize(); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h index 01ce6ec007..2239bdc118 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.h +++ b/src/plugins/platforms/wasm/qwasmintegration.h @@ -77,6 +77,7 @@ public: void addScreen(const QString &canvasId); void removeScreen(const QString &canvasId); + void resizeScreen(const QString &canvasId); private: mutable QWasmFontDatabase *m_fontDb; From 3b7db8ac90ba36949cb4168f07cc8dace47758a7 Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Fri, 29 Mar 2019 10:36:21 +0100 Subject: [PATCH 08/17] Fix assert/crash when creating QBrush with null QGradient MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The QBrush constructor taking a QGradient would assert or crash if passed a null (NoGradient) gradient. But it is not necessary for the API to be as brittle as that: instead the result can simply be a null QBrush object, i.e. the same as the default QBrush() constructor creates (style == NoBrush). This issue comes up now since with the recent introduction of QGradient presets, the API opens for using QGradient directly, whereas earlier, only the subclasses QLinearGradient etc. were to be used. Fixes: QTBUG-74648 Change-Id: I1a9b1c4654e4375aa6684700a262cc0946851448 Reviewed-by: Allan Sandfeld Jensen Reviewed-by: Tor Arne Vestbø --- src/gui/painting/qbrush.cpp | 12 ++++++++---- tests/auto/gui/painting/qbrush/tst_qbrush.cpp | 2 ++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp index 860653cc4c..bcc23fa683 100644 --- a/src/gui/painting/qbrush.cpp +++ b/src/gui/painting/qbrush.cpp @@ -545,9 +545,11 @@ QBrush::QBrush(const QBrush &other) */ QBrush::QBrush(const QGradient &gradient) { - Q_ASSERT_X(gradient.type() != QGradient::NoGradient, "QBrush::QBrush", - "QGradient should not be used directly, use the linear, radial\n" - "or conical gradients instead"); + if (Q_UNLIKELY(gradient.type() == QGradient::NoGradient)) { + d.reset(nullBrushInstance()); + d->ref.ref(); + return; + } const Qt::BrushStyle enum_table[] = { Qt::LinearGradientPattern, @@ -1376,8 +1378,10 @@ QGradient::QGradient(Preset preset) }(); const QJsonValue presetData = jsonPresets[preset - 1]; - if (!presetData.isObject()) + if (!presetData.isObject()) { + qWarning("QGradient: Undefined preset %i", preset); return; + } m_type = LinearGradient; setCoordinateMode(ObjectMode); diff --git a/tests/auto/gui/painting/qbrush/tst_qbrush.cpp b/tests/auto/gui/painting/qbrush/tst_qbrush.cpp index cd3eaa1478..ce6ce15767 100644 --- a/tests/auto/gui/painting/qbrush/tst_qbrush.cpp +++ b/tests/auto/gui/painting/qbrush/tst_qbrush.cpp @@ -345,6 +345,8 @@ void tst_QBrush::gradientPresets() QGradient invalidPreset(QGradient::Preset(-1)); QCOMPARE(invalidPreset.type(), QGradient::NoGradient); + QBrush brush(invalidPreset); + QCOMPARE(brush.style(), Qt::NoBrush); } void fill(QPaintDevice *pd) { From 6ccbe7ffdfee0a69ba50d22f577075b1d8cb0b04 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Fri, 29 Mar 2019 00:29:00 +0100 Subject: [PATCH 09/17] macOS: When a menu item has an italic font it should respect this MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Id8d2c5c0d0407ead66700d38634f342f489a2842 Fixes: QTBUG-69489 Reviewed-by: Morten Johan Sørvig --- src/plugins/styles/mac/qmacstyle_mac.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 9a11c4d818..fd006b1ca3 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -4323,7 +4323,8 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter d->setupNSGraphicsContext(cgCtx, YES); [s.toNSString() drawInRect:textRect - withAttributes:@{ NSFontAttributeName:f, NSForegroundColorAttributeName:c }]; + withAttributes:@{ NSFontAttributeName:f, NSForegroundColorAttributeName:c, + NSObliquenessAttributeName: [NSNumber numberWithDouble: myFont.italic() ? 0.3 : 0.0]}]; d->restoreNSGraphicsContext(cgCtx); } else { From 409e3eab092ae9896f453b69f4b4749e654680bb Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Thu, 28 Mar 2019 10:42:38 +0100 Subject: [PATCH 10/17] QMacStyle - fix PE_InticatorTabClose handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for the case a custom style sheet is in use and QStyleSheetStyle replaces the widget (close button) with its parent (QTabBar). We still need this button though to compare against tabButton on a hovered tab. This allows us to have, indeed, native-looking tabs as documented (aka similar to Safari or the "Terminal" application). Change-Id: I53ff78699e705db6d7c7b84774b8e188a1277535 Fixes: QTBUG-61092 Fixes: QTBUG-74689 Reviewed-by: Morten Johan Sørvig --- src/plugins/styles/mac/qmacstyle_mac.mm | 6 ++++-- src/widgets/styles/qstylesheetstyle.cpp | 9 ++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index fd006b1ca3..0745e917a2 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -3411,18 +3411,20 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai case PE_IndicatorTabClose: { // Make close button visible only on the hovered tab. QTabBar *tabBar = qobject_cast(w->parentWidget()); + const QWidget *closeBtn = w; if (!tabBar) { // QStyleSheetStyle instead of CloseButton (which has // a QTabBar as a parent widget) uses the QTabBar itself: tabBar = qobject_cast(const_cast(w)); + closeBtn = decltype(closeBtn)(property("_q_styleSheetRealCloseButton").value()); } if (tabBar) { const bool documentMode = tabBar->documentMode(); const QTabBarPrivate *tabBarPrivate = static_cast(QObjectPrivate::get(tabBar)); const int hoveredTabIndex = tabBarPrivate->hoveredTabIndex(); if (!documentMode || - (hoveredTabIndex != -1 && ((w == tabBar->tabButton(hoveredTabIndex, QTabBar::LeftSide)) || - (w == tabBar->tabButton(hoveredTabIndex, QTabBar::RightSide))))) { + (hoveredTabIndex != -1 && ((closeBtn == tabBar->tabButton(hoveredTabIndex, QTabBar::LeftSide)) || + (closeBtn == tabBar->tabButton(hoveredTabIndex, QTabBar::RightSide))))) { const bool hover = (opt->state & State_MouseOver); const bool selected = (opt->state & State_Selected); const bool pressed = (opt->state & State_Sunken); diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index 79fa20851f..73b147e622 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -4590,8 +4590,12 @@ void QStyleSheetStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *op break; #if QT_CONFIG(tabbar) case PE_IndicatorTabClose: - if (w) + if (w) { + // QMacStyle needs a real widget, not its parent - to implement + // 'document mode' properly, drawing nothing if a tab is not hovered. + baseStyle()->setProperty("_q_styleSheetRealCloseButton", QVariant::fromValue((void *)w)); w = w->parentWidget(); //match on the QTabBar instead of the CloseButton + } pseudoElement = PseudoElement_TabBarTabCloseButton; #endif @@ -4609,6 +4613,9 @@ void QStyleSheetStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *op } else { baseStyle()->drawPrimitive(pe, opt, p, w); } + + if (baseStyle()->property("_q_styleSheetRealCloseButton").toBool()) + baseStyle()->setProperty("_q_styleSheetRealCloseButton", QVariant(QVariant::Invalid)); } QPixmap QStyleSheetStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap& pixmap, From e4532224145a0a72cde9b40cb7fd39011624d1c1 Mon Sep 17 00:00:00 2001 From: Dmitry Kazakov Date: Sun, 10 Mar 2019 14:48:58 +0300 Subject: [PATCH 11/17] Fix tablet jitter on X11 We should get the correct stylus position from the valuators, not from the X11-provided global position. Global position is rounded to the nearest FP16 values, which is not enough for smooth painting. [ChangeLog][Platform Specific Changes][X11 / XCB] QTabletEvent coordinates now come from AbsX/AbsY valuators in the X11 event, in more precise 32.32 fixed-point format, scaled to fit the virtual desktop. It's possible to revert to using the legacy 16.16-format event_x/event_y coordinates as in previous releases by setting the QT_XCB_TABLET_LEGACY_COORDINATES environment variable. Task-number: QTBUG-45375 Fixes: QTBUG-48151 Change-Id: Ie701446b3586296bcb8fb09158f387ba6a7cbf07 Reviewed-by: Shawn Rutledge --- .../platforms/xcb/qxcbconnection_xi2.cpp | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 04ddd3c98c..91fd612cde 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -1208,6 +1208,11 @@ bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletD return handled; } +inline qreal scaleOneValuator(qreal normValue, qreal screenMin, qreal screenSize) +{ + return screenMin + normValue * screenSize; +} + void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletData) { auto *ev = reinterpret_cast(event); @@ -1220,6 +1225,17 @@ void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletD QPointF global(fixed1616ToReal(ev->root_x), fixed1616ToReal(ev->root_y)); double pressure = 0, rotation = 0, tangentialPressure = 0; int xTilt = 0, yTilt = 0; + static const bool useValuators = !qEnvironmentVariableIsSet("QT_XCB_TABLET_LEGACY_COORDINATES"); + + // Valuators' values are relative to the physical size of the current virtual + // screen. Therefore we cannot use QScreen/QWindow geometry and should use + // QPlatformWindow/QPlatformScreen instead. + QRect physicalScreenArea; + if (Q_LIKELY(useValuators)) { + const QList siblings = window->screen()->handle()->virtualSiblings(); + for (const QPlatformScreen *screen : siblings) + physicalScreenArea |= screen->geometry(); + } for (QHash::iterator it = tabletData->valuatorInfo.begin(), ite = tabletData->valuatorInfo.end(); it != ite; ++it) { @@ -1228,6 +1244,20 @@ void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletD xi2GetValuatorValueIfSet(event, classInfo.number, &classInfo.curVal); double normalizedValue = (classInfo.curVal - classInfo.minVal) / (classInfo.maxVal - classInfo.minVal); switch (valuator) { + case QXcbAtom::AbsX: + if (Q_LIKELY(useValuators)) { + const qreal value = scaleOneValuator(normalizedValue, physicalScreenArea.x(), physicalScreenArea.width()); + global.setX(value); + local.setX(value - window->handle()->geometry().x()); + } + break; + case QXcbAtom::AbsY: + if (Q_LIKELY(useValuators)) { + qreal value = scaleOneValuator(normalizedValue, physicalScreenArea.y(), physicalScreenArea.height()); + global.setY(value); + local.setY(value - window->handle()->geometry().y()); + } + break; case QXcbAtom::AbsPressure: pressure = normalizedValue; break; From 954b73445cfbfef01207d51d1b986c6dd796c6d0 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Mon, 1 Apr 2019 15:22:15 +0200 Subject: [PATCH 12/17] Refine underflow check in QLocaleData::convertDoubleToFloat() A string can parse as a non-zero double that's smaller than the smallest float yet be a faithful representation of the smallest float. So rather than testing for non-zero doubles less than the smallest float, test for non-zero doubles that cast to float zero; these underflow. This means small values close below the smallest float shall round up to it, rather than down to zero, requiring a tweak to an existing test. Added a test for the boundary case (and tidied the test data). Fixes: QTBUG-74833 Change-Id: I4cb30b3c0e54683574b98253505607caaf88fbfb Reviewed-by: Thiago Macieira --- src/corelib/tools/qlocale_p.h | 6 +-- .../corelib/tools/qlocale/tst_qlocale.cpp | 43 ++++++++++++------- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h index a96ecf1c1c..7487c9128c 100644 --- a/src/corelib/tools/qlocale_p.h +++ b/src/corelib/tools/qlocale_p.h @@ -252,10 +252,8 @@ public: const float huge = std::numeric_limits::infinity(); return d < 0 ? -huge : huge; } - if (std::fabs(d) >= std::numeric_limits::min() // i.e. d != 0 - && std::fabs(d) < std::numeric_limits::min()) { - // Values smaller than std::numeric_limits::min() have - // failed already; match them. + if (d != 0 && float(d) == 0) { + // Values that underflow double already failed. Match them: if (ok != 0) *ok = false; return 0; diff --git a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp b/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp index 5d344834e6..279ee2e8a0 100644 --- a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp +++ b/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp @@ -952,29 +952,42 @@ void tst_QLocale::stringToDouble() void tst_QLocale::stringToFloat_data() { + using Bounds = std::numeric_limits; toReal_data(); - if (std::numeric_limits::has_infinity) { - double huge = std::numeric_limits::infinity(); - QTest::newRow("C inf") << QString("C") << QString("inf") << true << huge; - QTest::newRow("C +inf") << QString("C") << QString("+inf") << true << +huge; - QTest::newRow("C -inf") << QString("C") << QString("-inf") << true << -huge; + const QString C(QStringLiteral("C")); + if (Bounds::has_infinity) { + double huge = Bounds::infinity(); + QTest::newRow("C inf") << C << QString("inf") << true << huge; + QTest::newRow("C +inf") << C << QString("+inf") << true << +huge; + QTest::newRow("C -inf") << C << QString("-inf") << true << -huge; // Overflow float, but not double: - QTest::newRow("C big") << QString("C") << QString("3.5e38") << false << huge; - QTest::newRow("C -big") << QString("C") << QString("-3.5e38") << false << -huge; + QTest::newRow("C big") << C << QString("3.5e38") << false << huge; + QTest::newRow("C -big") << C << QString("-3.5e38") << false << -huge; // Overflow double, too: - QTest::newRow("C huge") << QString("C") << QString("2e308") << false << huge; - QTest::newRow("C -huge") << QString("C") << QString("-2e308") << false << -huge; + QTest::newRow("C huge") << C << QString("2e308") << false << huge; + QTest::newRow("C -huge") << C << QString("-2e308") << false << -huge; } - if (std::numeric_limits::has_quiet_NaN) - QTest::newRow("C qnan") << QString("C") << QString("NaN") << true << double(std::numeric_limits::quiet_NaN()); + if (Bounds::has_quiet_NaN) + QTest::newRow("C qnan") << C << QString("NaN") << true << double(Bounds::quiet_NaN()); + + // Minimal float: shouldn't underflow + QTest::newRow("C float min") + << C << QLocale::c().toString(Bounds::denorm_min()) << true << double(Bounds::denorm_min()); + QTest::newRow("C float -min") + << C << QLocale::c().toString(-Bounds::denorm_min()) << true << -double(Bounds::denorm_min()); // Underflow float, but not double: - QTest::newRow("C small") << QString("C") << QString("1e-45") << false << 0.; - QTest::newRow("C -small") << QString("C") << QString("-1e-45") << false << 0.; + QTest::newRow("C small") << C << QString("7e-46") << false << 0.; + QTest::newRow("C -small") << C << QString("-7e-46") << false << 0.; + using Double = std::numeric_limits; + QTest::newRow("C double min") + << C << QLocale::c().toString(Double::denorm_min()) << false << 0.0; + QTest::newRow("C double -min") + << C << QLocale::c().toString(-Double::denorm_min()) << false << 0.0; // Underflow double, too: - QTest::newRow("C tiny") << QString("C") << QString("2e-324") << false << 0.; - QTest::newRow("C -tiny") << QString("C") << QString("-2e-324") << false << 0.; + QTest::newRow("C tiny") << C << QString("2e-324") << false << 0.; + QTest::newRow("C -tiny") << C << QString("-2e-324") << false << 0.; } void tst_QLocale::stringToFloat() From 685b8db13aa19e734f239678bae23607fcededbd Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Thu, 28 Mar 2019 16:49:57 +0300 Subject: [PATCH 13/17] Forward devicePixelRatio in QPixmap::mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also add a test checking that devicePixelRatio is forwarded to derivatives of QPixmap. Change-Id: Idb2b3f033ccc0fd49bf54b11f5dffbce5a19b006 Reviewed-by: Morten Johan Sørvig --- src/gui/image/qplatformpixmap.cpp | 1 + tests/auto/gui/image/qpixmap/tst_qpixmap.cpp | 34 ++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/gui/image/qplatformpixmap.cpp b/src/gui/image/qplatformpixmap.cpp index 2209c3de4d..a2e01147c4 100644 --- a/src/gui/image/qplatformpixmap.cpp +++ b/src/gui/image/qplatformpixmap.cpp @@ -178,6 +178,7 @@ QBitmap QPlatformPixmap::mask() const if (mask.isNull()) // allocation failed return QBitmap(); + mask.setDevicePixelRatio(devicePixelRatio()); mask.setColorCount(2); mask.setColor(0, QColor(Qt::color0).rgba()); mask.setColor(1, QColor(Qt::color1).rgba()); diff --git a/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp b/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp index 9a338ad55a..4d31d80246 100644 --- a/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp +++ b/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp @@ -121,6 +121,7 @@ private slots: void copy(); void deepCopyPreservesDpr(); + void dprPassthrough(); void depthOfNullObjects(); void transformed(); @@ -1169,6 +1170,39 @@ void tst_QPixmap::deepCopyPreservesDpr() QCOMPARE(dest.devicePixelRatio(), dpr); } +void tst_QPixmap::dprPassthrough() +{ + const qreal dpr = 2; + QPixmap src(32, 32); + src.setDevicePixelRatio(dpr); + src.fill(Qt::transparent); + QCOMPARE(src.devicePixelRatio(), dpr); + + QImage img = src.toImage(); + QCOMPARE(img.devicePixelRatio(), dpr); + + QPixmap pm(1, 1); + pm.convertFromImage(img); + QCOMPARE(pm.devicePixelRatio(), dpr); + + QBitmap heuristicMask = src.createHeuristicMask(); + QCOMPARE(heuristicMask.devicePixelRatio(), dpr); + + QBitmap maskFromColor = src.createMaskFromColor(Qt::white); + QCOMPARE(maskFromColor.devicePixelRatio(), dpr); + + QBitmap mask = src.mask(); + QCOMPARE(mask.devicePixelRatio(), dpr); + + QPixmap scaled = src.scaled(16, 16); + QCOMPARE(scaled.devicePixelRatio(), dpr); + + QTransform t; + t.rotate(90); + QPixmap transformed = src.transformed(t); + QCOMPARE(transformed.devicePixelRatio(), dpr); +} + void tst_QPixmap::depthOfNullObjects() { QBitmap b1; From 011794130c8e4bb64dbc3c8c9b50849b278cdda3 Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Thu, 28 Mar 2019 13:59:35 +0300 Subject: [PATCH 14/17] Forward physical parameters for derived QImages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit More specifically, for masks and rotated images. Add tests for it, also add tests that image metadata is forwarded for converted and copied images. Fixes: QTBUG-49259 Change-Id: I05d4a468b17f53a2625500b871c01b2c53b981a1 Reviewed-by: Morten Johan Sørvig --- src/gui/image/qimage.cpp | 36 ++++++++++++++++------ tests/auto/gui/image/qimage/tst_qimage.cpp | 35 +++++++++++++++++++++ 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 3e18ca6528..ed6f23ee56 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -1089,15 +1089,31 @@ void QImage::detach() } -static void copyMetadata(QImageData *dst, const QImageData *src) +static void copyPhysicalMetadata(QImageData *dst, const QImageData *src) { - // Doesn't copy colortable and alpha_clut, or offset. dst->dpmx = src->dpmx; dst->dpmy = src->dpmy; dst->devicePixelRatio = src->devicePixelRatio; +} + +static void copyMetadata(QImageData *dst, const QImageData *src) +{ + // Doesn't copy colortable and alpha_clut, or offset. + copyPhysicalMetadata(dst, src); dst->text = src->text; } +static void copyMetadata(QImage *dst, const QImage &src) +{ + dst->setDotsPerMeterX(src.dotsPerMeterX()); + dst->setDotsPerMeterY(src.dotsPerMeterY()); + dst->setDevicePixelRatio(src.devicePixelRatio()); + const auto textKeys = src.textKeys(); + for (const auto &key: textKeys) + dst->setText(key, src.text(key)); + +} + /*! \fn QImage QImage::copy(int x, int y, int width, int height) const \overload @@ -2924,8 +2940,10 @@ QImage QImage::createAlphaMask(Qt::ImageConversionFlags flags) const } QImage mask(d->width, d->height, Format_MonoLSB); - if (!mask.isNull()) + if (!mask.isNull()) { dither_to_Mono(mask.d, d, flags, true); + copyPhysicalMetadata(mask.d, d); + } return mask; } @@ -3043,6 +3061,7 @@ QImage QImage::createHeuristicMask(bool clipTight) const #undef PIX + copyPhysicalMetadata(m.d, d); return m; } #endif //QT_NO_IMAGE_HEURISTIC_MASK @@ -3086,6 +3105,8 @@ QImage QImage::createMaskFromColor(QRgb color, Qt::MaskMode mode) const } if (mode == Qt::MaskOutColor) maskImage.invertPixels(); + + copyPhysicalMetadata(maskImage.d, d); return maskImage; } @@ -4655,8 +4676,7 @@ QImage QImage::smoothScaled(int w, int h) const { static QImage rotated90(const QImage &image) { QImage out(image.height(), image.width(), image.format()); - out.setDotsPerMeterX(image.dotsPerMeterY()); - out.setDotsPerMeterY(image.dotsPerMeterX()); + copyMetadata(&out, image); if (image.colorCount() > 0) out.setColorTable(image.colorTable()); int w = image.width(); @@ -4684,8 +4704,7 @@ static QImage rotated180(const QImage &image) return image.mirrored(true, true); QImage out(image.width(), image.height(), image.format()); - out.setDotsPerMeterX(image.dotsPerMeterY()); - out.setDotsPerMeterY(image.dotsPerMeterX()); + copyMetadata(&out, image); if (image.colorCount() > 0) out.setColorTable(image.colorTable()); int w = image.width(); @@ -4697,8 +4716,7 @@ static QImage rotated180(const QImage &image) static QImage rotated270(const QImage &image) { QImage out(image.height(), image.width(), image.format()); - out.setDotsPerMeterX(image.dotsPerMeterY()); - out.setDotsPerMeterY(image.dotsPerMeterX()); + copyMetadata(&out, image); if (image.colorCount() > 0) out.setColorTable(image.colorTable()); int w = image.width(); diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp index 6bc27a6e16..bb81b9f61f 100644 --- a/tests/auto/gui/image/qimage/tst_qimage.cpp +++ b/tests/auto/gui/image/qimage/tst_qimage.cpp @@ -3260,11 +3260,46 @@ void tst_QImage::metadataPassthrough() QCOMPARE(mirrored.dotsPerMeterY(), a.dotsPerMeterY()); QCOMPARE(mirrored.devicePixelRatio(), a.devicePixelRatio()); + QTransform t; + t.rotate(90); + QImage rotated = a.transformed(t); + QCOMPARE(rotated.text(QStringLiteral("Test")), a.text(QStringLiteral("Test"))); + QCOMPARE(rotated.dotsPerMeterX(), a.dotsPerMeterX()); + QCOMPARE(rotated.dotsPerMeterY(), a.dotsPerMeterY()); + QCOMPARE(rotated.devicePixelRatio(), a.devicePixelRatio()); + QImage swapped = a.rgbSwapped(); QCOMPARE(swapped.text(QStringLiteral("Test")), a.text(QStringLiteral("Test"))); QCOMPARE(swapped.dotsPerMeterX(), a.dotsPerMeterX()); QCOMPARE(swapped.dotsPerMeterY(), a.dotsPerMeterY()); QCOMPARE(swapped.devicePixelRatio(), a.devicePixelRatio()); + + QImage converted = a.convertToFormat(QImage::Format_RGB32); + QCOMPARE(converted.text(QStringLiteral("Test")), a.text(QStringLiteral("Test"))); + QCOMPARE(converted.dotsPerMeterX(), a.dotsPerMeterX()); + QCOMPARE(converted.dotsPerMeterY(), a.dotsPerMeterY()); + QCOMPARE(converted.devicePixelRatio(), a.devicePixelRatio()); + + QImage copied = a.copy(0, 0, a.width() / 2, a.height() / 2); + QCOMPARE(copied.text(QStringLiteral("Test")), a.text(QStringLiteral("Test"))); + QCOMPARE(copied.dotsPerMeterX(), a.dotsPerMeterX()); + QCOMPARE(copied.dotsPerMeterY(), a.dotsPerMeterY()); + QCOMPARE(copied.devicePixelRatio(), a.devicePixelRatio()); + + QImage alphaMask = a.createAlphaMask(); + QCOMPARE(alphaMask.dotsPerMeterX(), a.dotsPerMeterX()); + QCOMPARE(alphaMask.dotsPerMeterY(), a.dotsPerMeterY()); + QCOMPARE(alphaMask.devicePixelRatio(), a.devicePixelRatio()); + + QImage heuristicMask = a.createHeuristicMask(); + QCOMPARE(heuristicMask.dotsPerMeterX(), a.dotsPerMeterX()); + QCOMPARE(heuristicMask.dotsPerMeterY(), a.dotsPerMeterY()); + QCOMPARE(heuristicMask.devicePixelRatio(), a.devicePixelRatio()); + + QImage maskFromColor = a.createMaskFromColor(qRgb(0, 0, 0)); + QCOMPARE(maskFromColor.dotsPerMeterX(), a.dotsPerMeterX()); + QCOMPARE(maskFromColor.dotsPerMeterY(), a.dotsPerMeterY()); + QCOMPARE(maskFromColor.devicePixelRatio(), a.devicePixelRatio()); } void tst_QImage::pixelColor() From 81ed119da1215c9dda5ff202cc1339eadb62bda4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Mon, 25 Mar 2019 14:54:58 +0100 Subject: [PATCH 15/17] wasm: make windows fullscreen by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (fullscreen as in use the entire canvas area, without showing window decorations) This is a better default for Qt on the web where window decorations are not common. We also avoid the “window close” trap, where there is no way to re-open a closed main window. Change-Id: Ie0fbf6ada3f49244bee765ea882acb473809e715 Reviewed-by: Lorn Potter --- src/plugins/platforms/wasm/qwasmintegration.cpp | 12 ++++++++++++ src/plugins/platforms/wasm/qwasmintegration.h | 1 + 2 files changed, 13 insertions(+) diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp index 55bb167fcc..374b2e7e32 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.cpp +++ b/src/plugins/platforms/wasm/qwasmintegration.cpp @@ -186,9 +186,21 @@ QAbstractEventDispatcher *QWasmIntegration::createEventDispatcher() const QVariant QWasmIntegration::styleHint(QPlatformIntegration::StyleHint hint) const { + if (hint == ShowIsFullScreen) + return true; + return QPlatformIntegration::styleHint(hint); } +Qt::WindowState QWasmIntegration::defaultWindowState(Qt::WindowFlags flags) const +{ + // Don't maximize dialogs + if (flags & Qt::Dialog & ~Qt::Window) + return Qt::WindowNoState; + + return QPlatformIntegration::defaultWindowState(flags); +} + QStringList QWasmIntegration::themeNames() const { return QStringList() << QLatin1String("webassembly"); diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h index 2239bdc118..ee0c7f769e 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.h +++ b/src/plugins/platforms/wasm/qwasmintegration.h @@ -67,6 +67,7 @@ public: QPlatformFontDatabase *fontDatabase() const override; QAbstractEventDispatcher *createEventDispatcher() const override; QVariant styleHint(QPlatformIntegration::StyleHint hint) const override; + Qt::WindowState defaultWindowState(Qt::WindowFlags flags) const override; QStringList themeNames() const override; QPlatformTheme *createPlatformTheme(const QString &name) const override; QPlatformClipboard *clipboard() const override; From 0683bbc67ccd5ad5d3a4c8afc6ed968b473bd2d3 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 2 Apr 2019 11:37:43 +0200 Subject: [PATCH 16/17] Fix remaining Q_DECL_OVERRIDE instances Change-Id: I512ea5a6c8cf2928b276af7f83f00a1df5879595 Reviewed-by: Friedemann Kleint --- .../doc/snippets/code/src_corelib_global_qglobal.cpp | 6 +++--- src/plugins/platforms/linuxfb/qlinuxfbintegration.h | 2 +- src/tools/uic/cpp/cppwriteincludes.h | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp b/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp index 03904659f5..eb75a29ca2 100644 --- a/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp @@ -773,16 +773,16 @@ bool readConfiguration(const QFile &file) //! [qdecloverride] // generate error if this doesn't actually override anything: - virtual void MyWidget::paintEvent(QPaintEvent*) Q_DECL_OVERRIDE; + virtual void MyWidget::paintEvent(QPaintEvent*) override; //! [qdecloverride] //! [qdeclfinal-1] // more-derived classes no longer permitted to override this: - virtual void MyWidget::paintEvent(QPaintEvent*) Q_DECL_FINAL; + virtual void MyWidget::paintEvent(QPaintEvent*) final; //! [qdeclfinal-1] //! [qdeclfinal-2] - class QRect Q_DECL_FINAL { // cannot be derived from + class QRect final { // cannot be derived from // ... }; //! [qdeclfinal-2] diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h index 7a871b3812..af6bd1d630 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h +++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h @@ -72,7 +72,7 @@ public: QList screens() const; - QFunctionPointer platformFunction(const QByteArray &function) const Q_DECL_OVERRIDE; + QFunctionPointer platformFunction(const QByteArray &function) const override; private: void createInputHandlers(); diff --git a/src/tools/uic/cpp/cppwriteincludes.h b/src/tools/uic/cpp/cppwriteincludes.h index 7f03849798..e9247f4cc4 100644 --- a/src/tools/uic/cpp/cppwriteincludes.h +++ b/src/tools/uic/cpp/cppwriteincludes.h @@ -58,9 +58,9 @@ struct WriteIncludes : public TreeWalker // // actions // - void acceptActionGroup(DomActionGroup *node) Q_DECL_OVERRIDE; - void acceptAction(DomAction *node) Q_DECL_OVERRIDE; - void acceptActionRef(DomActionRef *node) Q_DECL_OVERRIDE; + void acceptActionGroup(DomActionGroup *node) override; + void acceptAction(DomAction *node) override; + void acceptActionRef(DomActionRef *node) override; // // custom widgets From f99fe9cee9d35e1fabbf45364631f4a7f049ebe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Mon, 1 Apr 2019 18:41:23 +0200 Subject: [PATCH 17/17] wasm: implement QDesktopServices::openUrl() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Call window.open(url, ”_blank”) for a new tab. Change-Id: I227904f905262c7aedd086203ed816b53f66359c Reviewed-by: Lorn Potter --- .../platforms/wasm/qwasmintegration.cpp | 11 ++++- src/plugins/platforms/wasm/qwasmintegration.h | 4 +- src/plugins/platforms/wasm/qwasmservices.cpp | 45 +++++++++++++++++++ src/plugins/platforms/wasm/qwasmservices.h | 45 +++++++++++++++++++ src/plugins/platforms/wasm/wasm.pro | 6 ++- 5 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 src/plugins/platforms/wasm/qwasmservices.cpp create mode 100644 src/plugins/platforms/wasm/qwasmservices.h diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp index 374b2e7e32..e601d553f2 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.cpp +++ b/src/plugins/platforms/wasm/qwasmintegration.cpp @@ -34,6 +34,7 @@ #include "qwasmopenglcontext.h" #include "qwasmtheme.h" #include "qwasmclipboard.h" +#include "qwasmservices.h" #include "qwasmwindow.h" #ifndef QT_NO_OPENGL @@ -91,7 +92,7 @@ QWasmIntegration *QWasmIntegration::s_instance; QWasmIntegration::QWasmIntegration() : m_fontDb(nullptr), - m_eventDispatcher(nullptr), + m_desktopServices(nullptr), m_clipboard(new QWasmClipboard) { s_instance = this; @@ -119,6 +120,7 @@ QWasmIntegration::QWasmIntegration() QWasmIntegration::~QWasmIntegration() { delete m_fontDb; + delete m_desktopServices; for (auto it = m_screens.constBegin(); it != m_screens.constEnd(); ++it) QWindowSystemInterface::handleScreenRemoved(*it); @@ -213,6 +215,13 @@ QPlatformTheme *QWasmIntegration::createPlatformTheme(const QString &name) const return QPlatformIntegration::createPlatformTheme(name); } +QPlatformServices *QWasmIntegration::services() const +{ + if (m_desktopServices == nullptr) + m_desktopServices = new QWasmServices(); + return m_desktopServices; +} + QPlatformClipboard* QWasmIntegration::clipboard() const { return m_clipboard; diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h index ee0c7f769e..11d8d0f7f5 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.h +++ b/src/plugins/platforms/wasm/qwasmintegration.h @@ -50,6 +50,7 @@ class QWasmScreen; class QWasmCompositor; class QWasmBackingStore; class QWasmClipboard; +class QWasmServices; class QWasmIntegration : public QObject, public QPlatformIntegration { @@ -70,6 +71,7 @@ public: Qt::WindowState defaultWindowState(Qt::WindowFlags flags) const override; QStringList themeNames() const override; QPlatformTheme *createPlatformTheme(const QString &name) const override; + QPlatformServices *services() const override; QPlatformClipboard *clipboard() const override; QWasmClipboard *getWasmClipboard() { return m_clipboard; } @@ -82,7 +84,7 @@ public: private: mutable QWasmFontDatabase *m_fontDb; - mutable QWasmEventDispatcher *m_eventDispatcher; + mutable QWasmServices *m_desktopServices; mutable QHash m_backingStores; QHash m_screens; diff --git a/src/plugins/platforms/wasm/qwasmservices.cpp b/src/plugins/platforms/wasm/qwasmservices.cpp new file mode 100644 index 0000000000..9328b8c065 --- /dev/null +++ b/src/plugins/platforms/wasm/qwasmservices.cpp @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** 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 "qwasmservices.h" +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +bool QWasmServices::openUrl(const QUrl &url) +{ + QByteArray utf8Url = url.toString().toUtf8(); + emscripten::val::global("window").call("open", emscripten::val(utf8Url.constData()), emscripten::val("_blank")); + return true; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmservices.h b/src/plugins/platforms/wasm/qwasmservices.h new file mode 100644 index 0000000000..3b37f21f82 --- /dev/null +++ b/src/plugins/platforms/wasm/qwasmservices.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** 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 QWASMDESKTOPSERVICES_H +#define QWASMDESKTOPSERVICES_H + +#include + +QT_BEGIN_NAMESPACE + +class QWasmServices : public QPlatformServices +{ +public: + bool openUrl(const QUrl &url) override; +}; + +QT_END_NAMESPACE + +#endif // QWASMDESKTOPSERVICES_H diff --git a/src/plugins/platforms/wasm/wasm.pro b/src/plugins/platforms/wasm/wasm.pro index 5aa6dfccf3..9b98445c68 100644 --- a/src/plugins/platforms/wasm/wasm.pro +++ b/src/plugins/platforms/wasm/wasm.pro @@ -19,7 +19,8 @@ SOURCES = \ qwasmcursor.cpp \ qwasmopenglcontext.cpp \ qwasmtheme.cpp \ - qwasmclipboard.cpp + qwasmclipboard.cpp \ + qwasmservices.cpp HEADERS = \ qwasmintegration.h \ @@ -33,7 +34,8 @@ HEADERS = \ qwasmcursor.h \ qwasmopenglcontext.h \ qwasmtheme.h \ - qwasmclipboard.h + qwasmclipboard.h \ + qwasmservices.h wasmfonts.files = \ ../../../3rdparty/wasm/Vera.ttf \