diff --git a/mkspecs/devices/linux-rasp-pi4-v3d-g++/qmake.conf b/mkspecs/devices/linux-rasp-pi4-v3d-g++/qmake.conf new file mode 100644 index 0000000000..69b0c761a8 --- /dev/null +++ b/mkspecs/devices/linux-rasp-pi4-v3d-g++/qmake.conf @@ -0,0 +1,40 @@ +# qmake configuration for the Raspberry Pi 4 (32-bit) using the Mesa V3D +# graphics stack. (not the Broadcom stack) +# +# This supports accelerated OpenGL both for X11 and DRM/KMS. Perhaps +# Wayland too. +# +# Tested with a sysroot created from Raspbian Buster and a gcc 7.4 +# toolchain from Linaro. +# +# Example configure command line, assuming installation to +# /usr/local/qt5pi on device and ~/rpi/qt5 on the host: +# +# ./configure -release -opengl es2 -device linux-rasp-pi4-v3d-g++ -device-option CROSS_COMPILE=~/rpi/gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- \ +# -sysroot ~/rpi/sysroot -opensource -confirm-license -make libs -prefix /usr/local/qt5pi -extprefix ~/rpi/qt5 -v +# +# Check the configure output carefully. EGLFS, EGLFS GBM, and EGL on X11 +# should all be 'yes'. Otherwise something is wrong. +# +# If getting linker errors like "undefined reference to `_dl_stack_flags'" check the +# symlinks in the sysroot, they were probably not adjusted +# correctly. F.ex. sysroot/usr/lib/arm-linux-gnueabihf/libpthread.so must point to +# sysroot/lib/arm-linux-gnueabihf/libpthread.so.0. If it is a broken link instead, bad +# things will happen. + +include(../common/linux_device_pre.conf) + +QMAKE_LIBS_EGL += -lEGL +QMAKE_LIBS_OPENGL_ES2 += -lGLESv2 -lEGL + +QMAKE_CFLAGS = -march=armv8-a -mtune=cortex-a72 -mfpu=crypto-neon-fp-armv8 +QMAKE_CXXFLAGS = $$QMAKE_CFLAGS + +DISTRO_OPTS += hard-float +DISTRO_OPTS += deb-multi-arch + +EGLFS_DEVICE_INTEGRATION = eglfs_kms + +include(../common/linux_arm_device_post.conf) + +load(qt_config) diff --git a/mkspecs/devices/linux-rasp-pi4-v3d-g++/qplatformdefs.h b/mkspecs/devices/linux-rasp-pi4-v3d-g++/qplatformdefs.h new file mode 100644 index 0000000000..4435fb2557 --- /dev/null +++ b/mkspecs/devices/linux-rasp-pi4-v3d-g++/qplatformdefs.h @@ -0,0 +1,40 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +#include "../../linux-g++/qplatformdefs.h" diff --git a/mkspecs/features/mac/default_post.prf b/mkspecs/features/mac/default_post.prf index 26bd3e2e98..993f4d56a9 100644 --- a/mkspecs/features/mac/default_post.prf +++ b/mkspecs/features/mac/default_post.prf @@ -97,21 +97,22 @@ macx-xcode { qmake_pkginfo_typeinfo.value = "????" QMAKE_MAC_XCODE_SETTINGS += qmake_pkginfo_typeinfo - !isEmpty(VERSION) { - l = $$split(VERSION, '.') 0 0 # make sure there are at least three - VER_MAJ = $$member(l, 0, 0) - VER_MIN = $$member(l, 1, 1) - VER_PAT = $$member(l, 2, 2) - unset(l) + bundle_version = $$VERSION + isEmpty(bundle_version): bundle_version = 1.0.0 - qmake_full_version.name = QMAKE_FULL_VERSION - qmake_full_version.value = $${VER_MAJ}.$${VER_MIN}.$${VER_PAT} - QMAKE_MAC_XCODE_SETTINGS += qmake_full_version + l = $$split(bundle_version, '.') 0 0 # make sure there are at least three + VER_MAJ = $$member(l, 0, 0) + VER_MIN = $$member(l, 1, 1) + VER_PAT = $$member(l, 2, 2) + unset(l) - qmake_short_version.name = QMAKE_SHORT_VERSION - qmake_short_version.value = $${VER_MAJ}.$${VER_MIN} - QMAKE_MAC_XCODE_SETTINGS += qmake_short_version - } + qmake_full_version.name = QMAKE_FULL_VERSION + qmake_full_version.value = $${VER_MAJ}.$${VER_MIN}.$${VER_PAT} + QMAKE_MAC_XCODE_SETTINGS += qmake_full_version + + qmake_short_version.name = QMAKE_SHORT_VERSION + qmake_short_version.value = $${VER_MAJ}.$${VER_MIN} + QMAKE_MAC_XCODE_SETTINGS += qmake_short_version !isEmpty(QMAKE_XCODE_DEBUG_INFORMATION_FORMAT) { debug_information_format.name = DEBUG_INFORMATION_FORMAT diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index b178084690..5e54278dd1 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -2891,8 +2891,8 @@ On desktop Windows, the default value is the value of the environment variable \c{WindowsSDKVersion}. - On WinRT, the default value is the value of the environment variable - \c{UCRTVERSION}. + On Universal Windows Platform (UWP), the default value is the value of the + environment variable \c{UCRTVERSION}. \target WINDOWS_TARGET_PLATFORM_MIN_VERSION \section1 WINDOWS_TARGET_PLATFORM_MIN_VERSION @@ -2905,8 +2905,8 @@ \target WINRT_MANIFEST \section1 WINRT_MANIFEST - Specifies parameters to be passed to the application manifest on \l{Qt for WinRT}{Windows - Runtime}. The allowed values are: + Specifies parameters to be passed to the application manifest on + \l{Qt for UWP}{UWP}. The allowed values are: \table \header @@ -2941,7 +2941,6 @@ \row \li foreground \li Tile foreground (text) color. Defaults to \c{light}. - This option is only available for Windows Store apps on Windows 8 and Windows RT. \row \li iconic_tile_icon \li Image file for the \c{iconic} tile template icon. Default provided by @@ -2956,16 +2955,16 @@ manifest's UUID, or generates a new UUID if none is present. \row \li logo_30x30 - \li Logo image file of size 30x30 pixels. This is not supported on Windows Phone. + \li Logo image file of size 30x30 pixels. \row \li logo_41x41 - \li Logo image file of size 41x41 pixels. This is only supported on Windows Phone. + \li Logo image file of size 41x41 pixels. This parameter is obsolete. \row \li logo_70x70 - \li Logo image file of size 70x70 pixels. This is not supported on Windows Phone. + \li Logo image file of size 70x70 pixels. \row \li logo_71x71 - \li Logo image file of size 71x71 pixels. This is only supported on Windows Phone. + \li Logo image file of size 71x71 pixels. This parameter is obsolete. \row \li logo_150x150 \li Logo image file of size 150x150 pixels. This is supported on all Windows @@ -2980,31 +2979,27 @@ Store App platforms. \row \li logo_620x300 - \li Splash screen image file of size 620x300 pixels. This is not supported on - Windows Phone. + \li Splash screen image file of size 620x300 pixels. \row \li logo_480x800 - \li Splash screen image file of size 480x800 pixels. This is only supported on - Windows Phone. + \li Splash screen image file of size 480x800 pixels. + This parameter is obsolete. \row \li logo_large \li Large logo image file. This has to be 150x150 pixels. Supported on all Windows Store App platforms. Default provided by the mkspec. \row \li logo_medium - \li Medium logo image file. For Windows Phone the image must have a pixel size - of 71x71, for other Windows Store App platforms 70x70. Default provided by - the mkspec. + \li Medium logo image file. The image must have a pixel size of 70x70. + Default provided by the mkspec. \row \li logo_small - \li Small logo image file. For Windows Phone the image must have a pixel size - of 44x44, for other Windows Store App platforms 30x30. Default provided by - the mkspec. + \li Small logo image file. The image must have a pixel size of 30x30. + Default provided by the mkspec. \row \li logo_splash - \li Splash screen image file. For Windows Phone the image must have a pixel size - of 480x800, for other Windows Store App platforms 620x300. Default provided - by the mkspec. + \li Splash screen image file. The image must have a pixel size of + 620x300. Default provided by the mkspec. \row \li logo_store \li Logo image file for Windows Store. Default provided by the mkspec. @@ -3017,10 +3012,12 @@ \li The name of the package as displayed to the user. Defaults to TARGET. \row \li phone_product_id - \li The GUID of the product. Defaults to the value of WINRT_MANIFEST.identity. (Windows Phone only) + \li The GUID of the product. + This parameter is obsolete. \row \li phone_publisher_id - \li The GUID of the publisher. Defaults to an invalid GUID. (Windows Phone only) + \li The GUID of the publisher. + This parameter is obsolete. \row \li publisher \li Display name of the publisher. Defaults to \c{Default publisher display name}. @@ -3071,10 +3068,6 @@ WINRT_MANIFEST.CONFIG += verbatim \endcode - \note The required image sizes of \e logo_small, \e logo_medium, and \e logo_large - depend on the target platform. The general descriptions are overwritten if a - description that specifies the size is provided. - \target YACCSOURCES \section1 YACCSOURCES diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp index a4705136a2..54460aff77 100644 --- a/src/corelib/io/qfilesystemwatcher.cpp +++ b/src/corelib/io/qfilesystemwatcher.cpp @@ -451,6 +451,12 @@ QStringList QFileSystemWatcher::removePaths(const QStringList &paths) This signal is emitted when the file at the specified \a path is modified, renamed or removed from disk. + \note As a safety measure, many applications save an open file by + writing a new file and then deleting the old one. In your slot + function, you can check \c watcher.files().contains(path). + If it returns \c false, check whether the file still exists + and then call \c addPath() to continue watching it. + \sa directoryChanged() */ diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index c537e8f51b..e25049f821 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -2708,18 +2708,22 @@ QStringList QCoreApplication::libraryPathsLocked() QStringList *app_libpaths = new QStringList; coreappdata()->app_libpaths.reset(app_libpaths); - QString libPathEnv = qEnvironmentVariable("QT_PLUGIN_PATH"); - if (!libPathEnv.isEmpty()) { - QStringList paths = libPathEnv.split(QDir::listSeparator(), QString::SkipEmptyParts); - for (QStringList::const_iterator it = paths.constBegin(); it != paths.constEnd(); ++it) { - QString canonicalPath = QDir(*it).canonicalPath(); - if (!canonicalPath.isEmpty() - && !app_libpaths->contains(canonicalPath)) { - app_libpaths->append(canonicalPath); + auto setPathsFromEnv = [&](QString libPathEnv) { + if (!libPathEnv.isEmpty()) { + QStringList paths = libPathEnv.split(QDir::listSeparator(), QString::SkipEmptyParts); + for (QStringList::const_iterator it = paths.constBegin(); it != paths.constEnd(); ++it) { + QString canonicalPath = QDir(*it).canonicalPath(); + if (!canonicalPath.isEmpty() + && !app_libpaths->contains(canonicalPath)) { + app_libpaths->append(canonicalPath); + } } } - } - + }; + setPathsFromEnv(qEnvironmentVariable("QT_PLUGIN_PATH")); +#ifdef Q_OS_ANDROID + setPathsFromEnv(qEnvironmentVariable("QT_BUNDLED_LIBS_PATH")); +#endif #ifdef Q_OS_DARWIN // Check the main bundle's PlugIns directory as this is a standard location for Apple OSes. // Note that the QLibraryInfo::PluginsPath below will coincidentally be the same as this value diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index f62eac61ed..cf107498dd 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -3908,11 +3908,12 @@ void doActivate(QObject *sender, int signal_index, void **argv) if (connections->currentConnectionId.loadRelaxed() == 0) senderDeleted = true; } - if (!senderDeleted) + if (!senderDeleted) { sp->connections.loadRelaxed()->cleanOrphanedConnections(sender); - if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr) - signal_spy_set->signal_end_callback(sender, signal_index); + if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr) + signal_spy_set->signal_end_callback(sender, signal_index); + } } /*! @@ -4399,22 +4400,18 @@ QDebug operator<<(QDebug dbg, const QObject *o) \relates QObject \obsolete + In new code, you should prefer the use of the Q_ENUM() macro, which makes the + type available also to the meta type system. + For instance, QMetaEnum::fromType() will not work with types declared with Q_ENUMS(). + This macro registers one or several enum types to the meta-object system. - For example: - - \snippet code/src_corelib_kernel_qobject.cpp 38 - If you want to register an enum that is declared in another class, the enum must be fully qualified with the name of the class defining it. In addition, the class \e defining the enum has to inherit QObject as well as declare the enum using Q_ENUMS(). - In new code, you should prefer the use of the Q_ENUM() macro, which makes the - type available also to the meta type system. - For instance, QMetaEnum::fromType() will not work with types declared with Q_ENUMS(). - \sa {Qt's Property System} */ diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp index 6737aeccd2..79315ae50f 100644 --- a/src/corelib/plugin/qfactoryloader.cpp +++ b/src/corelib/plugin/qfactoryloader.cpp @@ -193,7 +193,11 @@ void QFactoryLoader::update() continue; d->loadedPaths << pluginDir; +#ifdef Q_OS_ANDROID + QString path = pluginDir; +#else QString path = pluginDir + d->suffix; +#endif if (qt_debug_component()) qDebug() << "QFactoryLoader::QFactoryLoader() checking directory path" << path << "..."; @@ -202,8 +206,10 @@ void QFactoryLoader::update() continue; QStringList plugins = QDir(path).entryList( -#ifdef Q_OS_WIN +#if defined(Q_OS_WIN) QStringList(QStringLiteral("*.dll")), +#elif defined(Q_OS_ANDROID) + QStringList(QLatin1String("plugins_%1_*.so").arg(d->suffix)), #endif QDir::Files); QLibraryPrivate *library = 0; @@ -339,6 +345,10 @@ QFactoryLoader::QFactoryLoader(const char *iid, #if QT_CONFIG(library) d->cs = cs; d->suffix = suffix; +# ifdef Q_OS_ANDROID + if (!d->suffix.isEmpty() && d->suffix.at(0) == QLatin1Char('/')) + d->suffix.remove(0, 1); +# endif QMutexLocker locker(qt_factoryloader_mutex()); update(); diff --git a/src/corelib/plugin/qlibrary_unix.cpp b/src/corelib/plugin/qlibrary_unix.cpp index 44d5513163..f0de1010d7 100644 --- a/src/corelib/plugin/qlibrary_unix.cpp +++ b/src/corelib/plugin/qlibrary_unix.cpp @@ -236,6 +236,14 @@ bool QLibraryPrivate::load_sys() auto attemptFromBundle = attempt; pHnd = dlopen(QFile::encodeName(attemptFromBundle.replace(QLatin1Char('/'), QLatin1Char('_'))), dlFlags); } + if (pHnd) { + using JniOnLoadPtr = jint (*)(JavaVM *vm, void *reserved); + JniOnLoadPtr jniOnLoad = reinterpret_cast(dlsym(pHnd, "JNI_OnLoad")); + if (jniOnLoad && jniOnLoad(QtAndroidPrivate::javaVM(), nullptr) == JNI_ERR) { + dlclose(pHnd); + pHnd = nullptr; + } + } #endif if (!pHnd && fileName.startsWith(QLatin1Char('/')) && QFile::exists(attempt)) { diff --git a/src/corelib/plugin/qpluginloader.cpp b/src/corelib/plugin/qpluginloader.cpp index 4e0c3a511b..cadff4f32b 100644 --- a/src/corelib/plugin/qpluginloader.cpp +++ b/src/corelib/plugin/qpluginloader.cpp @@ -311,6 +311,16 @@ static QString locatePlugin(const QString& fileName) for (const QString &path : qAsConst(paths)) { for (const QString &prefix : qAsConst(prefixes)) { for (const QString &suffix : qAsConst(suffixes)) { +#ifdef Q_OS_ANDROID + { + QString pluginPath = basePath + prefix + baseName + suffix; + const QString fn = path + QLatin1String("/lib") + pluginPath.replace(QLatin1Char('/'), QLatin1Char('_')); + if (debug) + qDebug() << "Trying..." << fn; + if (QFileInfo(fn).isFile()) + return fn; + } +#endif const QString fn = path + QLatin1Char('/') + basePath + prefix + baseName + suffix; if (debug) qDebug() << "Trying..." << fn; diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index bf00d4a9a3..dc33a83ac0 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -960,6 +960,7 @@ public: friend class QApplication; friend class QApplicationPrivate; friend class QQuickPointerTouchEvent; + friend class QQuickMultiPointTouchArea; }; #if QT_DEPRECATED_SINCE(5, 0) diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index edb363ac69..e5f752b94e 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -5658,44 +5658,63 @@ static inline void alphamapblend_argb32(quint32 *dst, int coverage, QRgba64 srcL { if (coverage == 0) { // nothing - } else if (coverage == 255) { - *dst = src; - } else if (!colorProfile) { - *dst = INTERPOLATE_PIXEL_255(src, coverage, *dst, 255 - coverage); + } else if (coverage == 255 || !colorProfile) { + blend_pixel(*dst, src, coverage); + } else if (*dst < 0xff000000) { + // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571 + blend_pixel(*dst, src, coverage); + } else if (src >= 0xff000000) { + grayBlendPixel(dst, coverage, srcLinear, colorProfile); } else { - if (*dst >= 0xff000000) { - grayBlendPixel(dst, coverage, srcLinear, colorProfile); - } else { - // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571 - *dst = INTERPOLATE_PIXEL_255(src, coverage, *dst, 255 - coverage); - } + // First do naive blend with text-color + QRgb s = *dst; + blend_pixel(s, src); + // Then gamma-corrected blend with glyph shape + QRgba64 s64 = colorProfile ? colorProfile->toLinear64(s) : QRgba64::fromArgb32(s); + grayBlendPixel(dst, coverage, s64, colorProfile); } } #if QT_CONFIG(raster_64bit) + +static inline void grayBlendPixel(QRgba64 &dst, int coverage, QRgba64 srcLinear, const QColorTrcLut *colorProfile) +{ + // Do a gammacorrected gray alphablend... + QRgba64 dstColor = dst; + if (colorProfile) { + if (dstColor.isOpaque()) + dstColor = colorProfile->toLinear(dstColor); + else if (!dstColor.isTransparent()) + dstColor = colorProfile->toLinear(dstColor.unpremultiplied()).premultiplied(); + } + + blend_pixel(dstColor, srcLinear, coverage); + + if (colorProfile) { + if (dstColor.isOpaque()) + dstColor = colorProfile->fromLinear(dstColor); + else if (!dstColor.isTransparent()) + dstColor = colorProfile->fromLinear(dstColor.unpremultiplied()).premultiplied(); + } + dst = dstColor; +} + static inline void alphamapblend_generic(int coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorTrcLut *colorProfile) { if (coverage == 0) { // nothing } else if (coverage == 255) { - dest[x] = src; + blend_pixel(dest[x], src); + } else if (src.isOpaque()) { + grayBlendPixel(dest[x], coverage, srcLinear, colorProfile); } else { - QRgba64 dstColor = dest[x]; - if (colorProfile) { - if (dstColor.isOpaque()) - dstColor = colorProfile->toLinear(dstColor); - else if (!dstColor.isTransparent()) - dstColor = colorProfile->toLinear(dstColor.unpremultiplied()).premultiplied(); - } - - dstColor = interpolate255(srcLinear, coverage, dstColor, 255 - coverage); - if (colorProfile) { - if (dstColor.isOpaque()) - dstColor = colorProfile->fromLinear(dstColor); - else if (!dstColor.isTransparent()) - dstColor = colorProfile->fromLinear(dstColor.unpremultiplied()).premultiplied(); - } - dest[x] = dstColor; + // First do naive blend with text-color + QRgba64 s = dest[x]; + blend_pixel(s, src); + // Then gamma-corrected blend with glyph shape + if (colorProfile) + s = colorProfile->toLinear(s); + grayBlendPixel(dest[x], coverage, s, colorProfile); } } @@ -5714,12 +5733,8 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer, colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text(); QRgba64 srcColor = color; - if (colorProfile) { - if (color.isOpaque()) - srcColor = colorProfile->toLinear(srcColor); - else - srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied(); - } + if (colorProfile && color.isOpaque()) + srcColor = colorProfile->toLinear(srcColor); alignas(8) QRgba64 buffer[BufferSize]; const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format]; @@ -5792,12 +5807,8 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer, colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text(); QRgba64 srcColor = color; - if (colorProfile) { - if (color.isOpaque()) - srcColor = colorProfile->toLinear(srcColor); - else - srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied(); - } + if (colorProfile && color.isOpaque()) + srcColor = colorProfile->toLinear(srcColor); quint32 buffer[BufferSize]; const DestFetchProc destFetch = destFetchProc[rasterBuffer->format]; @@ -5872,7 +5883,7 @@ void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer, int mapWidth, int mapHeight, int mapStride, const QClipData *clip, bool useGammaCorrection) { - if (useGammaCorrection) { + if (useGammaCorrection || !color.isOpaque()) { qt_alphamapblit_generic(rasterBuffer, x, y, color, map, mapWidth, mapHeight, mapStride, clip, useGammaCorrection); return; } @@ -5931,12 +5942,8 @@ static void qt_alphamapblit_argb32(QRasterBuffer *rasterBuffer, colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text(); QRgba64 srcColor = color; - if (colorProfile) { - if (color.isOpaque()) - srcColor = colorProfile->toLinear(srcColor); - else - srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied(); - } + if (colorProfile && color.isOpaque()) + srcColor = colorProfile->toLinear(srcColor); if (!clip) { quint32 *dest = reinterpret_cast(rasterBuffer->scanLine(y)) + x; @@ -6031,48 +6038,62 @@ static inline QRgb rgbBlend(QRgb d, QRgb s, uint rgbAlpha) #endif } +static inline void alphargbblend_argb32(quint32 *dst, uint coverage, const QRgba64 &srcLinear, quint32 src, const QColorTrcLut *colorProfile) +{ + if (coverage == 0xff000000) { + // nothing + } else if (coverage == 0xffffffff && qAlpha(src) == 255) { + blend_pixel(*dst, src); + } else if (!colorProfile) { + *dst = rgbBlend(*dst, src, coverage); + } else if (*dst < 0xff000000) { + // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571 + blend_pixel(*dst, src, qRgbAvg(coverage)); + } else if (srcLinear.isOpaque()) { + rgbBlendPixel(dst, coverage, srcLinear, colorProfile); + } else { + // First do naive blend with text-color + QRgb s = *dst; + blend_pixel(s, src); + // Then gamma-corrected blend with glyph shape + QRgba64 s64 = colorProfile ? colorProfile->toLinear64(s) : QRgba64::fromArgb32(s); + rgbBlendPixel(dst, coverage, s64, colorProfile); + } +} + #if QT_CONFIG(raster_64bit) +static inline void rgbBlendPixel(QRgba64 &dst, int coverage, QRgba64 slinear, const QColorTrcLut *colorProfile) +{ + // Do a gammacorrected RGB alphablend... + const QRgba64 dlinear = colorProfile ? colorProfile->toLinear64(dst) : dst; + + QRgba64 blend = rgbBlend(dlinear, slinear, coverage); + + dst = colorProfile ? colorProfile->fromLinear(blend) : blend; +} + static inline void alphargbblend_generic(uint coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorTrcLut *colorProfile) { if (coverage == 0xff000000) { // nothing } else if (coverage == 0xffffffff) { - dest[x] = src; + blend_pixel(dest[x], src); + } else if (!dest[x].isOpaque()) { + // Do a gray alphablend. + alphamapblend_generic(qRgbAvg(coverage), dest, x, srcLinear, src, colorProfile); + } else if (src.isOpaque()) { + rgbBlendPixel(dest[x], coverage, srcLinear, colorProfile); } else { - QRgba64 dstColor = dest[x]; - if (dstColor.isOpaque()) { - if (colorProfile) - dstColor = colorProfile->toLinear(dstColor); - dstColor = rgbBlend(dstColor, srcLinear, coverage); - if (colorProfile) - dstColor = colorProfile->fromLinear(dstColor); - dest[x] = dstColor; - } else { - // Do a gray alphablend. - alphamapblend_generic(qRgbAvg(coverage), dest, x, srcLinear, src, colorProfile); - } - } -} -#endif - -static inline void alphargbblend_argb32(quint32 *dst, uint coverage, const QRgba64 &srcLinear, quint32 src, const QColorTrcLut *colorProfile) -{ - if (coverage == 0xff000000) { - // nothing - } else if (coverage == 0xffffffff) { - *dst = src; - } else if (*dst < 0xff000000) { - // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571 - const int a = qRgbAvg(coverage); - *dst = INTERPOLATE_PIXEL_255(src, a, *dst, 255 - a); - } else if (!colorProfile) { - *dst = rgbBlend(*dst, src, coverage); - } else { - rgbBlendPixel(dst, coverage, srcLinear, colorProfile); + // First do naive blend with text-color + QRgba64 s = dest[x]; + blend_pixel(s, src); + // Then gamma-corrected blend with glyph shape + if (colorProfile) + s = colorProfile->toLinear(s); + rgbBlendPixel(dest[x], coverage, s, colorProfile); } } -#if QT_CONFIG(raster_64bit) static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 &color, const uint *src, int mapWidth, int mapHeight, int srcStride, @@ -6087,12 +6108,8 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer, colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text(); QRgba64 srcColor = color; - if (colorProfile) { - if (color.isOpaque()) - srcColor = colorProfile->toLinear(srcColor); - else - srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied(); - } + if (colorProfile && color.isOpaque()) + srcColor = colorProfile->toLinear(srcColor); alignas(8) QRgba64 buffer[BufferSize]; const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format]; @@ -6164,12 +6181,8 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer, colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text(); QRgba64 srcColor = color; - if (colorProfile) { - if (color.isOpaque()) - srcColor = colorProfile->toLinear(srcColor); - else - srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied(); - } + if (colorProfile && color.isOpaque()) + srcColor = colorProfile->toLinear(srcColor); quint32 buffer[BufferSize]; const DestFetchProc destFetch = destFetchProc[rasterBuffer->format]; @@ -6242,12 +6255,8 @@ static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer, colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text(); QRgba64 srcColor = color; - if (colorProfile) { - if (color.isOpaque()) - srcColor = colorProfile->toLinear(srcColor); - else - srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied(); - } + if (colorProfile && color.isOpaque()) + srcColor = colorProfile->toLinear(srcColor); if (!clip) { quint32 *dst = reinterpret_cast(rasterBuffer->scanLine(y)) + x; diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index 9c5d525722..dd42b96d79 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -671,6 +671,8 @@ static Q_ALWAYS_INLINE void blend_pixel(quint32 &dst, const quint32 src) static Q_ALWAYS_INLINE void blend_pixel(quint32 &dst, const quint32 src, const int const_alpha) { + if (const_alpha == 255) + return blend_pixel(dst, src); if (src != 0) { const quint32 s = BYTE_MUL(src, const_alpha); dst = s + BYTE_MUL(dst, qAlpha(~s)); diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 9894da8fe1..447ecb358a 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -842,8 +842,8 @@ void QRasterPaintEngine::updateRasterState() const QPainter::CompositionMode mode = s->composition_mode; s->flags.fast_text = (s->penData.type == QSpanData::Solid) && s->intOpacity == 256 - && (mode == QPainter::CompositionMode_Source - || (mode == QPainter::CompositionMode_SourceOver + && (mode == QPainter::CompositionMode_SourceOver + || (mode == QPainter::CompositionMode_Source && s->penData.solidColor.isOpaque())); } diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 84b34e390b..3ce54c20be 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -1716,8 +1716,8 @@ void QPainter::restore() static inline void qt_cleanup_painter_state(QPainterPrivate *d) { + qDeleteAll(d->states); d->states.clear(); - delete d->state; d->state = 0; d->engine = 0; d->device = 0; diff --git a/src/gui/painting/qrgba64_p.h b/src/gui/painting/qrgba64_p.h index ca879de27c..d145dbfbea 100644 --- a/src/gui/painting/qrgba64_p.h +++ b/src/gui/painting/qrgba64_p.h @@ -284,6 +284,8 @@ static Q_ALWAYS_INLINE void blend_pixel(QRgba64 &dst, QRgba64 src) static Q_ALWAYS_INLINE void blend_pixel(QRgba64 &dst, QRgba64 src, const int const_alpha) { + if (const_alpha == 255) + return blend_pixel(dst, src); if (!src.isTransparent()) { src = multiplyAlpha255(src, const_alpha); dst = src + multiplyAlpha65535(dst, 65535 - src.alpha()); diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index 0b1ab72c2c..bfd6944cdb 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -3524,7 +3524,10 @@ QSize QMetalSwapChain::surfacePixelSize() if (v) { CAMetalLayer *layer = (CAMetalLayer *) [v layer]; if (layer) { - CGSize size = [layer drawableSize]; + CGSize size = layer.bounds.size; + size.width *= layer.contentsScale; + size.height *= layer.contentsScale; + layer.drawableSize = size; return QSize(int(size.width), int(size.height)); } } diff --git a/src/plugins/platforms/android/android.pro b/src/plugins/platforms/android/android.pro index 346df84038..730247cd7f 100644 --- a/src/plugins/platforms/android/android.pro +++ b/src/plugins/platforms/android/android.pro @@ -1,9 +1,5 @@ TARGET = qtforandroid -# STATICPLUGIN needed because there's a Q_IMPORT_PLUGIN in androidjnimain.cpp -# Yes, the plugin imports itself statically -DEFINES += QT_STATICPLUGIN - LIBS += -ljnigraphics -landroid QT += \ @@ -19,7 +15,8 @@ INCLUDEPATH += \ $$PWD \ $$QT_SOURCE_TREE/src/3rdparty/android -SOURCES += $$PWD/androidplatformplugin.cpp \ +SOURCES += $$PWD/main.cpp \ + $$PWD/androidplatformplugin.cpp \ $$PWD/androidcontentfileengine.cpp \ $$PWD/androiddeadlockprotector.cpp \ $$PWD/androidjnimain.cpp \ @@ -92,4 +89,5 @@ qtConfig(vulkan) { } PLUGIN_TYPE = platforms +PLUGIN_CLASS_NAME = QAndroidIntegrationPlugin load(qt_plugin) diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 915f7f0f5b..27eb337aaa 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -68,8 +68,6 @@ #include -Q_IMPORT_PLUGIN(QAndroidPlatformIntegrationPlugin) - QT_BEGIN_NAMESPACE static JavaVM *m_javaVM = nullptr; diff --git a/src/plugins/platforms/android/main.cpp b/src/plugins/platforms/android/main.cpp new file mode 100644 index 0000000000..c304fc8d69 --- /dev/null +++ b/src/plugins/platforms/android/main.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2019 BogDan Vatra +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins 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 +#include "qandroidplatformintegration.h" + +QT_BEGIN_NAMESPACE + +class QAndroidIntegrationPlugin : public QPlatformIntegrationPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "android.json") + +public: + QPlatformIntegration *create(const QString& system, const QStringList& paramList) override; +}; + +QPlatformIntegration *QAndroidIntegrationPlugin::create(const QString& system, const QStringList& paramList) +{ + if (!system.compare(QLatin1String("android"), Qt::CaseInsensitive)) + return new QAndroidPlatformIntegration(paramList); + + return nullptr; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h index 5edd274759..d8eb6b7b7f 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.h +++ b/src/plugins/platforms/android/qandroidplatformwindow.h @@ -65,8 +65,8 @@ public: void setParent(const QPlatformWindow *window) override; WId winId() const override { return m_windowId; } - bool setMouseGrabEnabled(bool grab) override { return false; } - bool setKeyboardGrabEnabled(bool grab) override { return false; } + bool setMouseGrabEnabled(bool grab) override { Q_UNUSED(grab); return false; } + bool setKeyboardGrabEnabled(bool grab) override { Q_UNUSED(grab); return false; } QAndroidPlatformScreen *platformScreen() const; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index c6ce6e6819..fef72bc496 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -161,7 +161,6 @@ public: Q_NOTIFICATION_HANDLER(NSWindowDidOrderOffScreenNotification) void windowDidOrderOffScreen(); Q_NOTIFICATION_HANDLER(NSWindowDidChangeOcclusionStateNotification) void windowDidChangeOcclusionState(); Q_NOTIFICATION_HANDLER(NSWindowDidChangeScreenNotification) void windowDidChangeScreen(); - Q_NOTIFICATION_HANDLER(NSWindowDidChangeBackingPropertiesNotification) void windowDidChangeBackingProperties(); Q_NOTIFICATION_HANDLER(NSWindowWillCloseNotification) void windowWillClose(); bool windowShouldClose(); diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index db4bc12210..35b7162346 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1262,17 +1262,6 @@ void QCocoaWindow::windowDidChangeScreen() currentScreen->requestUpdate(); } } -/* - The window's backing scale factor or color space has changed. -*/ -void QCocoaWindow::windowDidChangeBackingProperties() -{ - // Ideally we would plumb this thought QPA in a way that lets clients - // invalidate their own caches, and recreate QBackingStore. For now we - // trigger an expose, and let QCocoaBackingStore deal with its own - // buffer invalidation. - [m_view setNeedsDisplay:YES]; -} void QCocoaWindow::windowWillClose() { diff --git a/src/plugins/platforms/cocoa/qnsview_drawing.mm b/src/plugins/platforms/cocoa/qnsview_drawing.mm index d2e6f848a0..e72142466b 100644 --- a/src/plugins/platforms/cocoa/qnsview_drawing.mm +++ b/src/plugins/platforms/cocoa/qnsview_drawing.mm @@ -173,20 +173,6 @@ } #endif -- (void)updateMetalLayerDrawableSize:(CAMetalLayer *)layer -{ - CGSize drawableSize = layer.bounds.size; - drawableSize.width *= layer.contentsScale; - drawableSize.height *= layer.contentsScale; - layer.drawableSize = drawableSize; -} - -- (void)layoutSublayersOfLayer:(CALayer *)layer -{ - if ([layer isKindOfClass:CAMetalLayer.class]) - [self updateMetalLayerDrawableSize:static_cast(layer)]; -} - - (void)displayLayer:(CALayer *)layer { if (!NSThread.isMainThread) { @@ -211,17 +197,16 @@ - (void)viewDidChangeBackingProperties { - CALayer *layer = self.layer; - if (!layer) - return; + qCDebug(lcQpaDrawing) << "Backing properties changed for" << self; - layer.contentsScale = self.window.backingScaleFactor; + if (self.layer) + self.layer.contentsScale = self.window.backingScaleFactor; - // Metal layers must be manually updated on e.g. screen change - if ([layer isKindOfClass:CAMetalLayer.class]) { - [self updateMetalLayerDrawableSize:static_cast(layer)]; - [self setNeedsDisplay:YES]; - } + // Ideally we would plumb this situation through QPA in a way that lets + // clients invalidate their own caches, recreate QBackingStore, etc. + // For now we trigger an expose, and let QCocoaBackingStore deal with + // buffer invalidation internally. + [self setNeedsDisplay:YES]; } @end diff --git a/src/sql/kernel/qsqldatabase.cpp b/src/sql/kernel/qsqldatabase.cpp index 99aa3e96c4..01726d79ef 100644 --- a/src/sql/kernel/qsqldatabase.cpp +++ b/src/sql/kernel/qsqldatabase.cpp @@ -881,6 +881,14 @@ bool QSqlDatabase::rollback() connection name must be passed to addDatabase() at connection object create time. + For the QSQLITE driver, if the database name specified does not + exist, then it will create the file for you unless the + QSQLITE_OPEN_READONLY option is set. + + Additionally, \a name can be set to \c ":memory:" which will + create a temporary database which is only available for the + lifetime of the application. + For the QOCI (Oracle) driver, the database name is the TNS Service Name. diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index 48d2e268b8..88c6c288e8 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -2735,6 +2735,11 @@ static void updateObjects(const QList& objects) if (auto widget = qobject_cast(const_cast(object))) { widget->style()->polish(widget); QCoreApplication::sendEvent(widget, &event); + QList children; + children.reserve(widget->children().size() + 1); + for (auto child: qAsConst(widget->children())) + children.append(child); + updateObjects(children); } } } diff --git a/src/widgets/widgets/qabstractspinbox.cpp b/src/widgets/widgets/qabstractspinbox.cpp index d49d9dbd66..fc19e0793e 100644 --- a/src/widgets/widgets/qabstractspinbox.cpp +++ b/src/widgets/widgets/qabstractspinbox.cpp @@ -1726,7 +1726,7 @@ void QAbstractSpinBox::initStyleOption(QStyleOptionSpinBox *option) const option->activeSubControls = d->hoverControl; } - option->stepEnabled = style()->styleHint(QStyle::SH_SpinControls_DisableOnBounds) + option->stepEnabled = style()->styleHint(QStyle::SH_SpinControls_DisableOnBounds, nullptr, this) ? stepEnabled() : (QAbstractSpinBox::StepDownEnabled|QAbstractSpinBox::StepUpEnabled); diff --git a/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp b/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp index 0a84b1fdd8..5697d21547 100644 --- a/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp +++ b/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp @@ -42,7 +42,11 @@ class tst_QNumeric: public QObject private slots: void fuzzyCompare_data(); void fuzzyCompare(); - void qNanInf(); + void rawNaN_data(); + void rawNaN(); + void generalNaN_data(); + void generalNaN(); + void infinity(); void classifyfp(); void floatDistance_data(); void floatDistance(); @@ -53,6 +57,8 @@ private slots: void mulOverflow_data(); void mulOverflow(); void signedOverflow(); +private: + void checkNaN(double nan); }; void tst_QNumeric::fuzzyCompare_data() @@ -92,44 +98,89 @@ void tst_QNumeric::fuzzyCompare() # pragma GCC optimize "no-fast-math" #endif -void tst_QNumeric::qNanInf() +void tst_QNumeric::checkNaN(double nan) { -#if defined __FAST_MATH__ && (__GNUC__ * 100 + __GNUC_MINOR__ < 404) - QSKIP("Non-conformant fast math mode is enabled, cannot run test"); -#endif - double nan = qQNaN(); +#define CHECKNAN(value) \ + do { \ + const double v = (value); \ + QCOMPARE(qFpClassify(v), FP_NAN); \ + QVERIFY(qIsNaN(v)); \ + QVERIFY(!qIsFinite(v)); \ + QVERIFY(!qIsInf(v)); \ + } while (0) + QVERIFY(!(0 > nan)); QVERIFY(!(0 < nan)); QVERIFY(!(0 == nan)); QVERIFY(!(nan == nan)); - QVERIFY(qIsNaN(nan)); - QVERIFY(qIsNaN(nan + 1)); - QVERIFY(qIsNaN(-nan)); - QVERIFY(qIsNaN(1.0 / nan)); - QVERIFY(qIsNaN(0.0 / nan)); - QVERIFY(qIsNaN(0.0 * nan)); - QCOMPARE(nan, nan); - QCOMPARE(nan, -nan); - Q_STATIC_ASSERT(sizeof(double) == 8); -#ifdef Q_LITTLE_ENDIAN - const uchar bytes[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f }; -#else - const uchar bytes[] = { 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; -#endif - memcpy(&nan, bytes, 8); - QVERIFY(!qIsFinite(nan)); - QVERIFY(!qIsInf(nan)); - QVERIFY(qIsNaN(nan)); - QVERIFY(qIsNaN(-nan)); - QVERIFY(!(nan == nan)); - QVERIFY(qIsNaN(0.0 * nan)); - QCOMPARE(qFpClassify(nan), FP_NAN); + CHECKNAN(nan); + CHECKNAN(nan + 1); + CHECKNAN(nan - 1); + CHECKNAN(-nan); + CHECKNAN(nan * 2.0); + CHECKNAN(nan / 2.0); + CHECKNAN(1.0 / nan); + CHECKNAN(0.0 / nan); + CHECKNAN(0.0 * nan); + + // When any NaN is expected, any NaN will do: QCOMPARE(nan, nan); QCOMPARE(nan, -nan); QCOMPARE(nan, qQNaN()); +#undef CHECKNAN +} - double inf = qInf(); +void tst_QNumeric::rawNaN_data() +{ +#if defined __FAST_MATH__ && (__GNUC__ * 100 + __GNUC_MINOR__ < 404) + QSKIP("Non-conformant fast math mode is enabled, cannot run test"); +#endif + QTest::addColumn("nan"); + + QTest::newRow("quiet") << qQNaN(); +} + +void tst_QNumeric::rawNaN() +{ + QFETCH(double, nan); + checkNaN(nan); +} + +void tst_QNumeric::generalNaN_data() +{ + QTest::addColumn("most"); + QTest::addColumn("next"); + QTest::addColumn("least"); + // Every value with every bit of the exponent set is a NaN. + // Sign and mantissa can be anything without interfering with that. + // The 0x7f bits of most and the 0xf0 bits of next are the exponent. + + QTest::newRow("lowload") << 0x7f << 0xf0 << 1; + QTest::newRow("sign-lowload") << 0xff << 0xf0 << 1; + QTest::newRow("highload") << 0x7f << 0xf1 << 0; + QTest::newRow("sign-highload") << 0xff << 0xf1 << 0; +} + +void tst_QNumeric::generalNaN() +{ + QFETCH(int, most); + QFETCH(int, next); + QFETCH(int, least); + double nan; + Q_STATIC_ASSERT(sizeof(double) == 8); +#ifdef Q_LITTLE_ENDIAN + const uchar bytes[] = { uchar(least), 0, 0, 0, 0, 0, uchar(next), uchar(most) }; +#else + const uchar bytes[] = { uchar(most), uchar(next), 0, 0, 0, 0, 0, uchar(least) }; +#endif + memcpy(&nan, bytes, 8); + checkNaN(nan); +} + +void tst_QNumeric::infinity() +{ + const double inf = qInf(); QVERIFY(inf > 0); QVERIFY(-inf < 0); QVERIFY(qIsInf(inf)); @@ -138,16 +189,23 @@ void tst_QNumeric::qNanInf() QVERIFY(qIsInf(-inf)); QVERIFY(qIsInf(inf + 1)); QVERIFY(qIsInf(inf - 1)); + QVERIFY(qIsInf(-inf - 1)); + QVERIFY(qIsInf(-inf + 1)); QVERIFY(qIsInf(inf * 2.0)); + QVERIFY(qIsInf(-inf * 2.0)); QVERIFY(qIsInf(inf / 2.0)); + QVERIFY(qIsInf(-inf / 2.0)); QVERIFY(qFuzzyCompare(1.0 / inf, 0.0)); QCOMPARE(1.0 / inf, 0.0); + QVERIFY(qFuzzyCompare(1.0 / -inf, 0.0)); + QCOMPARE(1.0 / -inf, 0.0); QVERIFY(qIsNaN(0.0 * inf)); + QVERIFY(qIsNaN(0.0 * -inf)); } void tst_QNumeric::classifyfp() { - QCOMPARE(qFpClassify(qQNaN()), FP_NAN); + // NaNs already handled, see checkNaN()'s callers. QCOMPARE(qFpClassify(qInf()), FP_INFINITE); QCOMPARE(qFpClassify(-qInf()), FP_INFINITE); diff --git a/tests/auto/testlib/selftests/expected_signaldumper.lightxml b/tests/auto/testlib/selftests/expected_signaldumper.lightxml index f68834e1a2..443f649bb6 100644 --- a/tests/auto/testlib/selftests/expected_signaldumper.lightxml +++ b/tests/auto/testlib/selftests/expected_signaldumper.lightxml @@ -568,11 +568,18 @@ + + + + + + + - + diff --git a/tests/auto/testlib/selftests/expected_signaldumper.tap b/tests/auto/testlib/selftests/expected_signaldumper.tap index 04d7d94745..e2d664f4f1 100644 --- a/tests/auto/testlib/selftests/expected_signaldumper.tap +++ b/tests/auto/testlib/selftests/expected_signaldumper.tap @@ -143,9 +143,11 @@ ok 18 - slotEmittingSignalOldSyntax(queued) # Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant()) # Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant()) ok 19 - variousTypes() -ok 20 - cleanupTestCase() -# Signal: QThread(_POINTER_) finished () -1..20 -# tests 20 -# pass 20 +# Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +ok 20 - deletingSender() +ok 21 - cleanupTestCase() +# Signal: QThread(_POINTER_) finished () +1..21 +# tests 21 +# pass 21 # fail 0 diff --git a/tests/auto/testlib/selftests/expected_signaldumper.teamcity b/tests/auto/testlib/selftests/expected_signaldumper.teamcity index 3b8cf8c54f..0fc568e086 100644 --- a/tests/auto/testlib/selftests/expected_signaldumper.teamcity +++ b/tests/auto/testlib/selftests/expected_signaldumper.teamcity @@ -56,6 +56,9 @@ ##teamcity[testStarted name='variousTypes()' flowId='tst_Signaldumper'] ##teamcity[testStdOut name='variousTypes()' out='INFO: Signal: SignalSlotClass(_POINTER_) qStringSignal (QString(Test string))|nINFO: Signal: SignalSlotClass(_POINTER_) qStringRefSignal ((QString&)@_POINTER_)|nINFO: Signal: SignalSlotClass(_POINTER_) qStringConstRefSignal (QString(Test string))|nINFO: Signal: SignalSlotClass(_POINTER_) qByteArraySignal (QByteArray(Test bytearray))|nINFO: Signal: SignalSlotClass(_POINTER_) qListSignal (QList())|nINFO: Signal: SignalSlotClass(_POINTER_) qVectorSignal (QVector())|nINFO: Signal: SignalSlotClass(_POINTER_) qVectorRefSignal ((QVector&)@_POINTER_)|nINFO: Signal: SignalSlotClass(_POINTER_) qVectorConstRefSignal (QVector())|nINFO: Signal: SignalSlotClass(_POINTER_) qVectorConstPointerSignal ((const QVector*)_POINTER_)|nINFO: Signal: SignalSlotClass(_POINTER_) qVectorPointerConstSignal ()|nINFO: Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant())|nINFO: Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant())' flowId='tst_Signaldumper'] ##teamcity[testFinished name='variousTypes()' flowId='tst_Signaldumper'] +##teamcity[testStarted name='deletingSender()' flowId='tst_Signaldumper'] +##teamcity[testStdOut name='deletingSender()' out='INFO: Signal: SignalSlotClass(_POINTER_) signalWithoutParameters ()' flowId='tst_Signaldumper'] +##teamcity[testFinished name='deletingSender()' flowId='tst_Signaldumper'] ##teamcity[testStarted name='cleanupTestCase()' flowId='tst_Signaldumper'] ##teamcity[testFinished name='cleanupTestCase()' flowId='tst_Signaldumper'] ##teamcity[testSuiteFinished name='tst_Signaldumper' flowId='tst_Signaldumper'] diff --git a/tests/auto/testlib/selftests/expected_signaldumper.txt b/tests/auto/testlib/selftests/expected_signaldumper.txt index f89c31afe5..0ee8cd38a2 100644 --- a/tests/auto/testlib/selftests/expected_signaldumper.txt +++ b/tests/auto/testlib/selftests/expected_signaldumper.txt @@ -143,7 +143,9 @@ INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qVe INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant()) INFO : tst_Signaldumper::variousTypes() Signal: SignalSlotClass(_POINTER_) qVariantSignal (QVariant()) PASS : tst_Signaldumper::variousTypes() +INFO : tst_Signaldumper::deletingSender() Signal: SignalSlotClass(_POINTER_) signalWithoutParameters () +PASS : tst_Signaldumper::deletingSender() PASS : tst_Signaldumper::cleanupTestCase() -INFO : tst_Signaldumper::UnknownTestFunc() Signal: QThread(_POINTER_) finished () -Totals: 20 passed, 0 failed, 0 skipped, 0 blacklisted, 0ms +INFO : tst_Signaldumper::UnknownTestFunc() Signal: QThread(_POINTER_) finished () +Totals: 21 passed, 0 failed, 0 skipped, 0 blacklisted, 0ms ********* Finished testing of tst_Signaldumper ********* diff --git a/tests/auto/testlib/selftests/expected_signaldumper.xml b/tests/auto/testlib/selftests/expected_signaldumper.xml index 82959c62df..f11a0c3ce6 100644 --- a/tests/auto/testlib/selftests/expected_signaldumper.xml +++ b/tests/auto/testlib/selftests/expected_signaldumper.xml @@ -570,12 +570,19 @@ + + + + + + + - + diff --git a/tests/auto/testlib/selftests/expected_signaldumper.xunitxml b/tests/auto/testlib/selftests/expected_signaldumper.xunitxml index 930dc97262..cbf7075ba1 100644 --- a/tests/auto/testlib/selftests/expected_signaldumper.xunitxml +++ b/tests/auto/testlib/selftests/expected_signaldumper.xunitxml @@ -1,5 +1,5 @@ - + @@ -151,8 +151,11 @@ + + + - + @@ -279,6 +282,7 @@ - + + diff --git a/tests/auto/testlib/selftests/signaldumper/tst_signaldumper.cpp b/tests/auto/testlib/selftests/signaldumper/tst_signaldumper.cpp index f6cd0d510e..08592e222d 100644 --- a/tests/auto/testlib/selftests/signaldumper/tst_signaldumper.cpp +++ b/tests/auto/testlib/selftests/signaldumper/tst_signaldumper.cpp @@ -56,6 +56,8 @@ private slots: void slotEmittingSignalOldSyntax(); void variousTypes(); + + void deletingSender(); }; void tst_Signaldumper::addConnectionTypeData() @@ -413,5 +415,14 @@ void tst_Signaldumper::variousTypes() emit signalSlotOwner.qVariantSignal(variant); } +void tst_Signaldumper::deletingSender() +{ + SignalSlotClass *signalSlotOwner = new SignalSlotClass(); + connect(signalSlotOwner, &SignalSlotClass::signalWithoutParameters, [signalSlotOwner]() { + delete signalSlotOwner; + }); + emit signalSlotOwner->signalWithoutParameters(); +} + QTEST_MAIN(tst_Signaldumper) #include "tst_signaldumper.moc" diff --git a/tests/manual/rhi/shadowmap/buildshaders.sh b/tests/manual/rhi/shadowmap/buildshaders.sh index c4d17841e6..8991bb074a 100755 --- a/tests/manual/rhi/shadowmap/buildshaders.sh +++ b/tests/manual/rhi/shadowmap/buildshaders.sh @@ -1,3 +1,4 @@ +#!/bin/sh qsb --glsl "120,300 es" --hlsl 50 --msl 12 shadowmap.vert -o shadowmap.vert.qsb qsb --glsl "120,300 es" --hlsl 50 --msl 12 shadowmap.frag -o shadowmap.frag.qsb qsb --glsl "120,300 es" --hlsl 50 --msl 12 main.vert -o main.vert.qsb