diff options
48 files changed, 929 insertions, 159 deletions
diff --git a/configure.json b/configure.json index 16a2af5bab..1f45f2ccb2 100644 --- a/configure.json +++ b/configure.json @@ -161,6 +161,7 @@ }, "sources": [ { "libs": "-lzdll", "condition": "config.msvc" }, + { "libs": "-lzlib", "condition": "config.msvc" }, { "libs": "-lz", "condition": "!config.msvc" } ] }, diff --git a/examples/widgets/widgets/tablet/mainwindow.cpp b/examples/widgets/widgets/tablet/mainwindow.cpp index 994666d4de..a048119533 100644 --- a/examples/widgets/widgets/tablet/mainwindow.cpp +++ b/examples/widgets/widgets/tablet/mainwindow.cpp @@ -104,15 +104,16 @@ void MainWindow::setEventCompression(bool compress) } //! [5] -void MainWindow::save() +bool MainWindow::save() { QString path = QDir::currentPath() + "/untitled.png"; QString fileName = QFileDialog::getSaveFileName(this, tr("Save Picture"), path); - - if (!m_canvas->saveImage(fileName)) + bool success = m_canvas->saveImage(fileName); + if (!success) QMessageBox::information(this, "Error Saving Picture", "Could not save the image"); + return success; } //! [5] @@ -128,6 +129,14 @@ void MainWindow::load() } //! [6] +void MainWindow::clear() +{ + if (QMessageBox::question(this, tr("Save changes"), tr("Do you want to save your changes?"), + QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, + QMessageBox::Save) != QMessageBox::Save || save()) + m_canvas->clear(); +} + //! [7] void MainWindow::about() { @@ -142,6 +151,7 @@ void MainWindow::createMenus() QMenu *fileMenu = menuBar()->addMenu(tr("&File")); fileMenu->addAction(tr("&Open..."), this, &MainWindow::load, QKeySequence::Open); fileMenu->addAction(tr("&Save As..."), this, &MainWindow::save, QKeySequence::SaveAs); + fileMenu->addAction(tr("&New"), this, &MainWindow::clear, QKeySequence::New); fileMenu->addAction(tr("E&xit"), this, &MainWindow::close, QKeySequence::Quit); QMenu *brushMenu = menuBar()->addMenu(tr("&Brush")); diff --git a/examples/widgets/widgets/tablet/mainwindow.h b/examples/widgets/widgets/tablet/mainwindow.h index 4b99324f04..4be28784b5 100644 --- a/examples/widgets/widgets/tablet/mainwindow.h +++ b/examples/widgets/widgets/tablet/mainwindow.h @@ -72,8 +72,9 @@ private slots: void setLineWidthValuator(QAction *action); void setSaturationValuator(QAction *action); void setEventCompression(bool compress); - void save(); + bool save(); void load(); + void clear(); void about(); private: diff --git a/examples/widgets/widgets/tablet/tabletcanvas.cpp b/examples/widgets/widgets/tablet/tabletcanvas.cpp index 73678ab754..3ff26d2ec8 100644 --- a/examples/widgets/widgets/tablet/tabletcanvas.cpp +++ b/examples/widgets/widgets/tablet/tabletcanvas.cpp @@ -90,6 +90,12 @@ bool TabletCanvas::loadImage(const QString &file) } //! [2] +void TabletCanvas::clear() +{ + m_pixmap.fill(Qt::white); + update(); +} + //! [3] void TabletCanvas::tabletEvent(QTabletEvent *event) { diff --git a/examples/widgets/widgets/tablet/tabletcanvas.h b/examples/widgets/widgets/tablet/tabletcanvas.h index 671d5376f8..c63ef76893 100644 --- a/examples/widgets/widgets/tablet/tabletcanvas.h +++ b/examples/widgets/widgets/tablet/tabletcanvas.h @@ -79,6 +79,7 @@ public: bool saveImage(const QString &file); bool loadImage(const QString &file); + void clear(); void setAlphaChannelValuator(Valuator type) { m_alphaChannelValuator = type; } void setColorSaturationValuator(Valuator type) diff --git a/mkspecs/common/macx.conf b/mkspecs/common/macx.conf index 7017d60e71..810b94fc9e 100644 --- a/mkspecs/common/macx.conf +++ b/mkspecs/common/macx.conf @@ -5,6 +5,9 @@ QMAKE_PLATFORM += macos osx macx QMAKE_MAC_SDK = macosx +QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.11 +QMAKE_APPLE_DEVICE_ARCHS = x86_64 + device.sdk = macosx device.target = device device.dir_affix = $${device.sdk} diff --git a/mkspecs/macx-clang/qmake.conf b/mkspecs/macx-clang/qmake.conf index 14c885fd78..464f327ac4 100644 --- a/mkspecs/macx-clang/qmake.conf +++ b/mkspecs/macx-clang/qmake.conf @@ -2,10 +2,6 @@ # qmake configuration for Clang on OS X # -QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.11 - -QMAKE_APPLE_DEVICE_ARCHS = x86_64 - # Opt-in xcb QPA support with XQuartz: # # configure \ diff --git a/mkspecs/macx-g++/qmake.conf b/mkspecs/macx-g++/qmake.conf index 5686610b17..d0e0026f1e 100644 --- a/mkspecs/macx-g++/qmake.conf +++ b/mkspecs/macx-g++/qmake.conf @@ -10,10 +10,6 @@ MAKEFILE_GENERATOR = UNIX CONFIG += app_bundle incremental global_init_link_order lib_version_first QMAKE_INCREMENTAL_STYLE = sublib -QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.11 - -QMAKE_APPLE_DEVICE_ARCHS = x86_64 - include(../common/macx.conf) include(../common/gcc-base-mac.conf) include(../common/g++-macx.conf) diff --git a/mkspecs/macx-icc/qmake.conf b/mkspecs/macx-icc/qmake.conf index bf3854c7c5..4daad497af 100644 --- a/mkspecs/macx-icc/qmake.conf +++ b/mkspecs/macx-icc/qmake.conf @@ -29,9 +29,5 @@ QMAKE_LFLAGS_HEADERPAD = -headerpad_max_install_names QMAKE_LFLAGS_VERSION = -current_version$${LITERAL_WHITESPACE} QMAKE_LFLAGS_COMPAT_VERSION = -compatibility_version$${LITERAL_WHITESPACE} -QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.11 - -QMAKE_APPLE_DEVICE_ARCHS = x86_64 - include(../common/macx.conf) load(qt_config) diff --git a/mkspecs/win32-icc/qmake.conf b/mkspecs/win32-icc/qmake.conf index 3cb0d58824..2447c712b1 100644 --- a/mkspecs/win32-icc/qmake.conf +++ b/mkspecs/win32-icc/qmake.conf @@ -12,6 +12,7 @@ include(../common/msvc-desktop.conf) # modifications to msvc-desktop.conf QMAKE_COMPILER += intel_icl +DEFINES += _ENABLE_EXTENDED_ALIGNED_STORAGE QMAKE_CFLAGS_OPTIMIZE_FULL = -O3 diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index e3c51f4be0..37144dcf17 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -383,7 +383,8 @@ \value AltModifier An Alt key on the keyboard is pressed. \value MetaModifier A Meta key on the keyboard is pressed. \value KeypadModifier A keypad button is pressed. - \value GroupSwitchModifier X11 only. A Mode_switch key on the keyboard is pressed. + \value GroupSwitchModifier X11 only (unless activated on Windows by a command line argument). + A Mode_switch key on the keyboard is pressed. \omitvalue KeyboardModifierMask diff --git a/src/corelib/io/qloggingcategory.cpp b/src/corelib/io/qloggingcategory.cpp index d8402c4eb6..aa84f56368 100644 --- a/src/corelib/io/qloggingcategory.cpp +++ b/src/corelib/io/qloggingcategory.cpp @@ -471,8 +471,6 @@ void QLoggingCategory::setFilterRules(const QString &rules) \note Arguments are not processed if debug output for the category is not enabled, so do not rely on any side effects. - \note Using the macro is thread-safe. - \sa qDebug() */ @@ -493,8 +491,6 @@ void QLoggingCategory::setFilterRules(const QString &rules) \note Arguments might not be processed if debug output for the category is not enabled, so do not rely on any side effects. - \note Using the macro is thread-safe. - \sa qDebug() */ @@ -518,8 +514,6 @@ void QLoggingCategory::setFilterRules(const QString &rules) \note Arguments are not processed if debug output for the category is not enabled, so do not rely on any side effects. - \note Using the macro is thread-safe. - \sa qInfo() */ @@ -540,8 +534,6 @@ void QLoggingCategory::setFilterRules(const QString &rules) \note Arguments might not be processed if debug output for the category is not enabled, so do not rely on any side effects. - \note Using the macro is thread-safe. - \sa qInfo() */ @@ -565,8 +557,6 @@ void QLoggingCategory::setFilterRules(const QString &rules) \note Arguments are not processed if warning output for the category is not enabled, so do not rely on any side effects. - \note Using the macro is thread-safe. - \sa qWarning() */ @@ -587,8 +577,6 @@ void QLoggingCategory::setFilterRules(const QString &rules) \note Arguments might not be processed if warning output for the category is not enabled, so do not rely on any side effects. - \note Using the macro is thread-safe. - \sa qWarning() */ @@ -612,8 +600,6 @@ void QLoggingCategory::setFilterRules(const QString &rules) \note Arguments are not processed if critical output for the category is not enabled, so do not rely on any side effects. - \note Using the macro is thread-safe. - \sa qCritical() */ @@ -634,8 +620,6 @@ void QLoggingCategory::setFilterRules(const QString &rules) \note Arguments might not be processed if critical output for the category is not enabled, so do not rely on any side effects. - \note Using the macro is thread-safe. - \sa qCritical() */ /*! diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/src/corelib/itemmodels/qsortfilterproxymodel.cpp index d8b4c8cc97..6b59b0723b 100644 --- a/src/corelib/itemmodels/qsortfilterproxymodel.cpp +++ b/src/corelib/itemmodels/qsortfilterproxymodel.cpp @@ -2347,7 +2347,7 @@ bool QSortFilterProxyModel::insertRows(int row, int count, const QModelIndex &pa if (row > m->source_rows.count()) return false; int source_row = (row >= m->source_rows.count() - ? m->source_rows.count() + ? m->proxy_rows.count() : m->source_rows.at(row)); return d->model->insertRows(source_row, count, source_parent); } @@ -2367,7 +2367,7 @@ bool QSortFilterProxyModel::insertColumns(int column, int count, const QModelInd if (column > m->source_columns.count()) return false; int source_column = (column >= m->source_columns.count() - ? m->source_columns.count() + ? m->proxy_columns.count() : m->source_columns.at(column)); return d->model->insertColumns(source_column, count, source_parent); } diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h index a6bd7847a5..b74b1fd123 100644 --- a/src/corelib/tools/qvarlengtharray.h +++ b/src/corelib/tools/qvarlengtharray.h @@ -490,7 +490,7 @@ Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthA } } else { T *b = ptr + offset; - memmove(b + 1, b, (s - offset) * sizeof(T)); + memmove(static_cast<void *>(b + 1), static_cast<const void *>(b), (s - offset) * sizeof(T)); new (b) T(std::move(t)); } s += 1; @@ -518,7 +518,7 @@ Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthA } else { T *b = ptr + offset; T *i = b + n; - memmove(i, b, (s - offset - n) * sizeof(T)); + memmove(static_cast<void *>(i), static_cast<const void *>(b), (s - offset - n) * sizeof(T)); while (i != b) new (--i) T(copy); } @@ -544,7 +544,7 @@ Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthA i->~T(); } } else { - memmove(ptr + f, ptr + l, (s - l) * sizeof(T)); + memmove(static_cast<void *>(ptr + f), static_cast<const void *>(ptr + l), (s - l) * sizeof(T)); } s -= n; return ptr + f; diff --git a/src/gui/configure.json b/src/gui/configure.json index 8e6569c069..26a5ae9a3d 100644 --- a/src/gui/configure.json +++ b/src/gui/configure.json @@ -294,7 +294,7 @@ }, "sources": [ { "libs": "-llibjpeg", "condition": "config.msvc" }, - { "libs": "-ljpeg", "condition": "!config.msvc" } + "-ljpeg" ] }, "libpng": { @@ -305,7 +305,9 @@ }, "sources": [ { "type": "pkgConfig", "args": "libpng" }, + { "libs": "-llibpng16", "condition": "config.msvc" }, { "libs": "-llibpng", "condition": "config.msvc" }, + { "libs": "-lpng16", "condition": "!config.msvc" }, { "libs": "-lpng", "condition": "!config.msvc" } ], "use": [ diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 32ef67763a..8a4c6b7fda 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -1829,7 +1829,14 @@ void QImage::fill(const QColor &color) else fill((uint) 0); break; - case QImage::Format_RGBX64: + case QImage::Format_RGBX64: { + QRgba64 c = color.rgba64(); + c.setAlpha(65535); + qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), c, + 0, 0, d->width, d->height, d->bytes_per_line); + break; + + } case QImage::Format_RGBA64: case QImage::Format_RGBA64_Premultiplied: qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), color.rgba64(), @@ -4616,6 +4623,11 @@ QImage QImage::smoothScaled(int w, int h) const { case QImage::Format_RGBX8888: #endif case QImage::Format_RGBA8888_Premultiplied: + case QImage::Format_RGBX64: + case QImage::Format_RGBA64_Premultiplied: + break; + case QImage::Format_RGBA64: + src = src.convertToFormat(QImage::Format_RGBA64_Premultiplied); break; default: if (src.hasAlphaChannel()) diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index f5527354a2..6f8ea6dc70 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -4163,7 +4163,7 @@ QDebug operator<<(QDebug dbg, const QEvent *e) const QNativeGestureEvent *ne = static_cast<const QNativeGestureEvent *>(e); dbg << "QNativeGestureEvent("; QtDebugUtils::formatQEnum(dbg, ne->gestureType()); - dbg << "localPos="; + dbg << ", localPos="; QtDebugUtils::formatQPoint(dbg, ne->localPos()); dbg << ", value=" << ne->value() << ')'; } diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 40d82d9269..93e8b6ee8f 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -594,6 +594,9 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME By default, they will be used if the application is not an instance of QApplication or for Qt Quick Controls 2 applications. + + \li \c {altgr}, detect the key \c {AltGr} found on some keyboards as + Qt::GroupSwitchModifier. \endlist The following parameter is available for \c {-platform cocoa} (on macOS): diff --git a/src/gui/opengl/qopengltextureuploader.cpp b/src/gui/opengl/qopengltextureuploader.cpp index fc449d8090..2428baed93 100644 --- a/src/gui/opengl/qopengltextureuploader.cpp +++ b/src/gui/opengl/qopengltextureuploader.cpp @@ -140,9 +140,12 @@ qsizetype QOpenGLTextureUploader::textureImage(GLenum target, const QImage &imag // No support for direct ARGB32 upload. break; } +#else + // Big endian requires GL_UNSIGNED_INT_8_8_8_8_REV for ARGB to match BGRA + break; +#endif } targetFormat = image.format(); -#endif break; case QImage::Format_BGR30: case QImage::Format_A2BGR30_Premultiplied: @@ -310,6 +313,11 @@ qsizetype QOpenGLTextureUploader::textureImage(GLenum target, const QImage &imag if (newSize != tx.size()) tx = tx.scaled(newSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + // Handle cases where the QImage is actually a sub image of its image data: + qsizetype naturalBpl = ((qsizetype(tx.width()) * tx.depth() + 31) >> 5) << 2; + if (tx.bytesPerLine() != naturalBpl) + tx = tx.copy(tx.rect()); + funcs->glTexImage2D(target, 0, internalFormat, tx.width(), tx.height(), 0, externalFormat, pixelType, tx.constBits()); qsizetype cost = qint64(tx.width()) * tx.height() * tx.depth() / 8; diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index b1424b5b0a..8f189994f1 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -342,7 +342,7 @@ static void QT_FASTCALL convertToRGB32(uint *buffer, int count, const QVector<QR buffer[i] = convertPixelToRGB32<Format>(buffer[i]); } -#if defined(__SSE2__) && !defined(__SSSE3__) +#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3 extern const uint * QT_FASTCALL fetchPixelsBPP24_ssse3(uint *dest, const uchar*src, int index, int count); #endif @@ -351,7 +351,7 @@ static const uint *QT_FASTCALL fetchRGBToRGB32(uint *buffer, const uchar *src, i const QVector<QRgb> *, QDitherInfo *) { constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>(); -#if defined(__SSE2__) && !defined(__SSSE3__) +#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3 if (BPP == QPixelLayout::BPP24 && qCpuHasFeature(SSSE3)) { // With SSE2 can convertToRGB32 be vectorized, but it takes SSSE3 // to vectorize the deforested version below. @@ -442,7 +442,7 @@ static const uint *QT_FASTCALL fetchARGBPMToARGB32PM(uint *buffer, const uchar * const QVector<QRgb> *, QDitherInfo *) { constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>(); -#if defined(__SSE2__) && !defined(__SSSE3__) +#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3 if (BPP == QPixelLayout::BPP24 && qCpuHasFeature(SSSE3)) { // With SSE2 can convertToRGB32 be vectorized, but it takes SSSE3 // to vectorize the deforested version below. @@ -640,6 +640,19 @@ void QT_FASTCALL rbSwap<QImage::Format_RGBA8888>(uchar *d, const uchar *s, int c { return rbSwap_rgb32(d, s, count); } +#else +template<> +void QT_FASTCALL rbSwap<QImage::Format_RGBA8888>(uchar *d, const uchar *s, int count) +{ + const uint *src = reinterpret_cast<const uint *>(s); + uint *dest = reinterpret_cast<uint *>(d); + for (int i = 0; i < count; ++i) { + const uint c = src[i]; + const uint rb = c & 0xff00ff00; + const uint ga = c & 0x00ff00ff; + dest[i] = ga | (rb << 16) | (rb >> 16); + } +} #endif static void QT_FASTCALL rbSwap_rgb30(uchar *d, const uchar *s, int count) @@ -2264,43 +2277,6 @@ static inline uint interpolate_4_pixels_16(uint tl, uint tr, uint bl, uint br, u } #endif -#if defined(__SSE2__) -static inline QRgba64 interpolate_4_pixels_rgb64(const QRgba64 t[], const QRgba64 b[], uint distx, uint disty) -{ - __m128i vt = _mm_loadu_si128((const __m128i*)t); - if (disty) { - __m128i vb = _mm_loadu_si128((const __m128i*)b); - vt = _mm_mulhi_epu16(vt, _mm_set1_epi16(0x10000 - disty)); - vb = _mm_mulhi_epu16(vb, _mm_set1_epi16(disty)); - vt = _mm_add_epi16(vt, vb); - } - if (distx) { - const __m128i vdistx = _mm_shufflelo_epi16(_mm_cvtsi32_si128(distx), _MM_SHUFFLE(0, 0, 0, 0)); - const __m128i vidistx = _mm_shufflelo_epi16(_mm_cvtsi32_si128(0x10000 - distx), _MM_SHUFFLE(0, 0, 0, 0)); - vt = _mm_mulhi_epu16(vt, _mm_unpacklo_epi64(vidistx, vdistx)); - vt = _mm_add_epi16(vt, _mm_srli_si128(vt, 8)); - } -#ifdef Q_PROCESSOR_X86_64 - return QRgba64::fromRgba64(_mm_cvtsi128_si64(vt)); -#else - QRgba64 out; - _mm_storel_epi64((__m128i*)&out, vt); - return out; -#endif -} -#else -static inline QRgba64 interpolate_4_pixels_rgb64(const QRgba64 t[], const QRgba64 b[], uint distx, uint disty) -{ - const uint dx = distx>>8; - const uint dy = disty>>8; - const uint idx = 256 - dx; - const uint idy = 256 - dy; - QRgba64 xtop = interpolate256(t[0], idx, t[1], dx); - QRgba64 xbot = interpolate256(b[0], idx, b[1], dx); - return interpolate256(xtop, idy, xbot, dy); -} -#endif - template<TextureBlendType blendType> void fetchTransformedBilinear_pixelBounds(int max, int l1, int l2, int &v1, int &v2); diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index 078ab62251..fb08261205 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -747,6 +747,77 @@ static constexpr inline bool hasFastInterpolate4() { return false; } #endif +static inline QRgba64 multiplyAlpha256(QRgba64 rgba64, uint alpha256) +{ + return QRgba64::fromRgba64((rgba64.red() * alpha256) >> 8, + (rgba64.green() * alpha256) >> 8, + (rgba64.blue() * alpha256) >> 8, + (rgba64.alpha() * alpha256) >> 8); +} +static inline QRgba64 interpolate256(QRgba64 x, uint alpha1, QRgba64 y, uint alpha2) +{ + return QRgba64::fromRgba64(multiplyAlpha256(x, alpha1) + multiplyAlpha256(y, alpha2)); +} + +#ifdef __SSE2__ +static inline QRgba64 interpolate_4_pixels_rgb64(const QRgba64 t[], const QRgba64 b[], uint distx, uint disty) +{ + __m128i vt = _mm_loadu_si128((const __m128i*)t); + if (disty) { + __m128i vb = _mm_loadu_si128((const __m128i*)b); + vt = _mm_mulhi_epu16(vt, _mm_set1_epi16(0x10000 - disty)); + vb = _mm_mulhi_epu16(vb, _mm_set1_epi16(disty)); + vt = _mm_add_epi16(vt, vb); + } + if (distx) { + const __m128i vdistx = _mm_shufflelo_epi16(_mm_cvtsi32_si128(distx), _MM_SHUFFLE(0, 0, 0, 0)); + const __m128i vidistx = _mm_shufflelo_epi16(_mm_cvtsi32_si128(0x10000 - distx), _MM_SHUFFLE(0, 0, 0, 0)); + vt = _mm_mulhi_epu16(vt, _mm_unpacklo_epi64(vidistx, vdistx)); + vt = _mm_add_epi16(vt, _mm_srli_si128(vt, 8)); + } +#ifdef Q_PROCESSOR_X86_64 + return QRgba64::fromRgba64(_mm_cvtsi128_si64(vt)); +#else + QRgba64 out; + _mm_storel_epi64((__m128i*)&out, vt); + return out; +#endif // Q_PROCESSOR_X86_64 +} +#elif defined(__ARM_NEON__) +static inline QRgba64 interpolate_4_pixels_rgb64(const QRgba64 t[], const QRgba64 b[], uint distx, uint disty) +{ + uint64x1x2_t vt = vld2_u64(reinterpret_cast<const uint64_t *>(t)); + if (disty) { + uint64x1x2_t vb = vld2_u64(reinterpret_cast<const uint64_t *>(b)); + uint32x4_t vt0 = vmull_n_u16(vreinterpret_u16_u64(vt.val[0]), 0x10000 - disty); + uint32x4_t vt1 = vmull_n_u16(vreinterpret_u16_u64(vt.val[1]), 0x10000 - disty); + vt0 = vmlal_n_u16(vt0, vreinterpret_u16_u64(vb.val[0]), disty); + vt1 = vmlal_n_u16(vt1, vreinterpret_u16_u64(vb.val[1]), disty); + vt.val[0] = vreinterpret_u64_u16(vshrn_n_u32(vt0, 16)); + vt.val[1] = vreinterpret_u64_u16(vshrn_n_u32(vt1, 16)); + } + if (distx) { + uint32x4_t vt0 = vmull_n_u16(vreinterpret_u16_u64(vt.val[0]), 0x10000 - distx); + vt0 = vmlal_n_u16(vt0, vreinterpret_u16_u64(vt.val[1]), distx); + vt.val[0] = vreinterpret_u64_u16(vshrn_n_u32(vt0, 16)); + } + QRgba64 out; + vst1_u64(reinterpret_cast<uint64_t *>(&out), vt.val[0]); + return out; +} +#else +static inline QRgba64 interpolate_4_pixels_rgb64(const QRgba64 t[], const QRgba64 b[], uint distx, uint disty) +{ + const uint dx = distx>>8; + const uint dy = disty>>8; + const uint idx = 256 - dx; + const uint idy = 256 - dy; + QRgba64 xtop = interpolate256(t[0], idx, t[1], dx); + QRgba64 xbot = interpolate256(b[0], idx, b[1], dx); + return interpolate256(xtop, idy, xbot, dy); +} +#endif // __SSE2__ + #if Q_BYTE_ORDER == Q_BIG_ENDIAN static Q_ALWAYS_INLINE quint32 RGBA2ARGB(quint32 x) { quint32 rgb = x >> 8; diff --git a/src/gui/painting/qimagescale.cpp b/src/gui/painting/qimagescale.cpp index 22787b91fe..ca7930500e 100644 --- a/src/gui/painting/qimagescale.cpp +++ b/src/gui/painting/qimagescale.cpp @@ -41,6 +41,7 @@ #include "qimage.h" #include "qcolor.h" +#include "qrgba64_p.h" QT_BEGIN_NAMESPACE @@ -85,7 +86,7 @@ QT_BEGIN_NAMESPACE * #ifdef'ed code, and removal of unneeded border calculation code. * Later the code has been refactored, an SSE4.1 optimizated path have been * added instead of the removed MMX assembler, and scaling of clipped area - * removed. + * removed, and an RGBA64 version written * * Imlib2 is (C) Carsten Haitzler and various contributors. The MMX code * is by Willem Monsuwe <willem@stack.nl>. All other modifications are @@ -94,12 +95,11 @@ QT_BEGIN_NAMESPACE namespace QImageScale { - const unsigned int** qimageCalcYPoints(const unsigned int *src, int sw, int sh, int dh); - int* qimageCalcXPoints(int sw, int dw); - int* qimageCalcApoints(int s, int d, int up); - QImageScaleInfo* qimageFreeScaleInfo(QImageScaleInfo *isi); - QImageScaleInfo *qimageCalcScaleInfo(const QImage &img, int sw, int sh, - int dw, int dh, char aa); + static const unsigned int** qimageCalcYPoints(const unsigned int *src, int sw, int sh, int dh); + static int* qimageCalcXPoints(int sw, int dw); + static int* qimageCalcApoints(int s, int d, int up); + static QImageScaleInfo* qimageFreeScaleInfo(QImageScaleInfo *isi); + static QImageScaleInfo *qimageCalcScaleInfo(const QImage &img, int sw, int sh, int dw, int dh, char aa); } using namespace QImageScale; @@ -108,8 +108,8 @@ using namespace QImageScale; // Code ported from Imlib... // -const unsigned int** QImageScale::qimageCalcYPoints(const unsigned int *src, - int sw, int sh, int dh) +static const unsigned int** QImageScale::qimageCalcYPoints(const unsigned int *src, + int sw, int sh, int dh) { const unsigned int **p; int j = 0, rv = 0; @@ -138,7 +138,7 @@ const unsigned int** QImageScale::qimageCalcYPoints(const unsigned int *src, return(p); } -int* QImageScale::qimageCalcXPoints(int sw, int dw) +static int* QImageScale::qimageCalcXPoints(int sw, int dw) { int *p, j = 0, rv = 0; qint64 val, inc; @@ -167,7 +167,7 @@ int* QImageScale::qimageCalcXPoints(int sw, int dw) return p; } -int* QImageScale::qimageCalcApoints(int s, int d, int up) +static int* QImageScale::qimageCalcApoints(int s, int d, int up) { int *p, j = 0, rv = 0; @@ -214,7 +214,7 @@ int* QImageScale::qimageCalcApoints(int s, int d, int up) return p; } -QImageScaleInfo* QImageScale::qimageFreeScaleInfo(QImageScaleInfo *isi) +static QImageScaleInfo* QImageScale::qimageFreeScaleInfo(QImageScaleInfo *isi) { if (isi) { delete[] isi->xpoints; @@ -226,9 +226,9 @@ QImageScaleInfo* QImageScale::qimageFreeScaleInfo(QImageScaleInfo *isi) return 0; } -QImageScaleInfo* QImageScale::qimageCalcScaleInfo(const QImage &img, - int sw, int sh, - int dw, int dh, char aa) +static QImageScaleInfo* QImageScale::qimageCalcScaleInfo(const QImage &img, + int sw, int sh, + int dw, int dh, char aa) { QImageScaleInfo *isi; int scw, sch; @@ -333,7 +333,7 @@ static void qt_qimageScaleAARGBA_up_xy(QImageScaleInfo *isi, unsigned int *dest, } } -/* scale by area sampling */ +/* scale by area sampling - with alpha */ static void qt_qimageScaleAARGBA(QImageScaleInfo *isi, unsigned int *dest, int dw, int dh, int dow, int sow) { @@ -529,6 +529,204 @@ static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *des } } +static void qt_qimageScaleRgba64_up_x_down_y(QImageScaleInfo *isi, QRgba64 *dest, + int dw, int dh, int dow, int sow); + +static void qt_qimageScaleRgba64_down_x_up_y(QImageScaleInfo *isi, QRgba64 *dest, + int dw, int dh, int dow, int sow); + +static void qt_qimageScaleRgba64_down_xy(QImageScaleInfo *isi, QRgba64 *dest, + int dw, int dh, int dow, int sow); + +static void qt_qimageScaleRgba64_up_xy(QImageScaleInfo *isi, QRgba64 *dest, + int dw, int dh, int dow, int sow) +{ + const QRgba64 **ypoints = (const QRgba64 **)isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + for (int y = 0; y < dh; y++) { + const QRgba64 *sptr = ypoints[y]; + QRgba64 *dptr = dest + (y * dow); + const int yap = yapoints[y]; + if (yap > 0) { + for (int x = 0; x < dw; x++) { + const QRgba64 *pix = sptr + xpoints[x]; + const int xap = xapoints[x]; + if (xap > 0) + *dptr = interpolate_4_pixels_rgb64(pix, pix + sow, xap * 256, yap * 256); + else + *dptr = interpolate256(pix[0], 256 - yap, pix[sow], yap); + dptr++; + } + } else { + for (int x = 0; x < dw; x++) { + const QRgba64 *pix = sptr + xpoints[x]; + const int xap = xapoints[x]; + *dptr = interpolate256(pix[0], 256 - xap, pix[1], xap); + dptr++; + } + } + } +} + +void qt_qimageScaleRgba64(QImageScaleInfo *isi, QRgba64 *dest, + int dw, int dh, int dow, int sow) +{ + if (isi->xup_yup == 3) + qt_qimageScaleRgba64_up_xy(isi, dest, dw, dh, dow, sow); + else if (isi->xup_yup == 1) + qt_qimageScaleRgba64_up_x_down_y(isi, dest, dw, dh, dow, sow); + else if (isi->xup_yup == 2) + qt_qimageScaleRgba64_down_x_up_y(isi, dest, dw, dh, dow, sow); + else + qt_qimageScaleRgba64_down_xy(isi, dest, dw, dh, dow, sow); +} + +inline static void qt_qimageScaleRgba64_helper(const QRgba64 *pix, int xyap, int Cxy, int step, qint64 &r, qint64 &g, qint64 &b, qint64 &a) +{ + r = pix->red() * xyap; + g = pix->green() * xyap; + b = pix->blue() * xyap; + a = pix->alpha() * xyap; + int j; + for (j = (1 << 14) - xyap; j > Cxy; j -= Cxy ){ + pix += step; + r += pix->red() * Cxy; + g += pix->green() * Cxy; + b += pix->blue() * Cxy; + a += pix->alpha() * Cxy; + } + pix += step; + r += pix->red() * j; + g += pix->green() * j; + b += pix->blue() * j; + a += pix->alpha() * j; +} + +static void qt_qimageScaleRgba64_up_x_down_y(QImageScaleInfo *isi, QRgba64 *dest, + int dw, int dh, int dow, int sow) +{ + const QRgba64 **ypoints = (const QRgba64 **)isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + for (int y = 0; y < dh; y++) { + int Cy = (yapoints[y]) >> 16; + int yap = (yapoints[y]) & 0xffff; + + QRgba64 *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + const QRgba64 *sptr = ypoints[y] + xpoints[x]; + qint64 r, g, b, a; + qt_qimageScaleRgba64_helper(sptr, yap, Cy, sow, r, g, b, a); + + int xap = xapoints[x]; + if (xap > 0) { + qint64 rr, gg, bb, aa; + qt_qimageScaleRgba64_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa); + + r = r * (256 - xap); + g = g * (256 - xap); + b = b * (256 - xap); + a = a * (256 - xap); + r = (r + (rr * xap)) >> 8; + g = (g + (gg * xap)) >> 8; + b = (b + (bb * xap)) >> 8; + a = (a + (aa * xap)) >> 8; + } + *dptr++ = qRgba64(r >> 14, g >> 14, b >> 14, a >> 14); + } + } +} + +static void qt_qimageScaleRgba64_down_x_up_y(QImageScaleInfo *isi, QRgba64 *dest, + int dw, int dh, int dow, int sow) +{ + const QRgba64 **ypoints = (const QRgba64 **)isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + for (int y = 0; y < dh; y++) { + QRgba64 *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const QRgba64 *sptr = ypoints[y] + xpoints[x]; + qint64 r, g, b, a; + qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, r, g, b, a); + + int yap = yapoints[y]; + if (yap > 0) { + qint64 rr, gg, bb, aa; + qt_qimageScaleRgba64_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa); + + r = r * (256 - yap); + g = g * (256 - yap); + b = b * (256 - yap); + a = a * (256 - yap); + r = (r + (rr * yap)) >> 8; + g = (g + (gg * yap)) >> 8; + b = (b + (bb * yap)) >> 8; + a = (a + (aa * yap)) >> 8; + } + *dptr = qRgba64(r >> 14, g >> 14, b >> 14, a >> 14); + dptr++; + } + } +} + +static void qt_qimageScaleRgba64_down_xy(QImageScaleInfo *isi, QRgba64 *dest, + int dw, int dh, int dow, int sow) +{ + const QRgba64 **ypoints = (const QRgba64 **)isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + for (int y = 0; y < dh; y++) { + int Cy = (yapoints[y]) >> 16; + int yap = (yapoints[y]) & 0xffff; + + QRgba64 *dptr = dest + (y * dow); + for (int x = 0; x < dw; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const QRgba64 *sptr = ypoints[y] + xpoints[x]; + qint64 rx, gx, bx, ax; + qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); + + qint64 r = rx * yap; + qint64 g = gx * yap; + qint64 b = bx * yap; + qint64 a = ax * yap; + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + sptr += sow; + qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); + r += rx * Cy; + g += gx * Cy; + b += bx * Cy; + a += ax * Cy; + } + sptr += sow; + qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); + r += rx * j; + g += gx * j; + b += bx * j; + a += ax * j; + + *dptr = qRgba64(r >> 28, g >> 28, b >> 28, a >> 28); + dptr++; + } + } +} + static void qt_qimageScaleAARGB_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest, int dw, int dh, int dow, int sow); @@ -745,7 +943,10 @@ QImage qSmoothScaleImage(const QImage &src, int dw, int dh) return QImage(); } - if (src.hasAlphaChannel()) + if (src.depth() > 32) + qt_qimageScaleRgba64(scaleinfo, (QRgba64 *)buffer.scanLine(0), + dw, dh, dw, src.bytesPerLine() / 8); + else if (src.hasAlphaChannel()) qt_qimageScaleAARGBA(scaleinfo, (unsigned int *)buffer.scanLine(0), dw, dh, dw, src.bytesPerLine() / 4); else diff --git a/src/gui/painting/qrgba64_p.h b/src/gui/painting/qrgba64_p.h index 1ed0e82182..b7e4d4d905 100644 --- a/src/gui/painting/qrgba64_p.h +++ b/src/gui/painting/qrgba64_p.h @@ -64,14 +64,6 @@ inline QRgba64 combineAlpha256(QRgba64 rgba64, uint alpha256) return QRgba64::fromRgba64(rgba64.red(), rgba64.green(), rgba64.blue(), (rgba64.alpha() * alpha256) >> 8); } -inline QRgba64 multiplyAlpha256(QRgba64 rgba64, uint alpha256) -{ - return QRgba64::fromRgba64((rgba64.red() * alpha256) >> 8, - (rgba64.green() * alpha256) >> 8, - (rgba64.blue() * alpha256) >> 8, - (rgba64.alpha() * alpha256) >> 8); -} - inline QRgba64 multiplyAlpha65535(QRgba64 rgba64, uint alpha65535) { return QRgba64::fromRgba64(qt_div_65535(rgba64.red() * alpha65535), @@ -126,11 +118,6 @@ inline T multiplyAlpha255(T rgba64, uint alpha255) #endif } -inline QRgba64 interpolate256(QRgba64 x, uint alpha1, QRgba64 y, uint alpha2) -{ - return QRgba64::fromRgba64(multiplyAlpha256(x, alpha1) + multiplyAlpha256(y, alpha2)); -} - inline QRgba64 interpolate255(QRgba64 x, uint alpha1, QRgba64 y, uint alpha2) { return QRgba64::fromRgba64(multiplyAlpha255(x, alpha1) + multiplyAlpha255(y, alpha2)); diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 6826f62b61..4e9b00f9c9 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1043,19 +1043,31 @@ struct QBidiAlgorithm { } } - bool process() + bool checkForBidi() const { - memset(analysis, 0, length * sizeof(QScriptAnalysis)); - - bool hasBidi = (baseLevel != 0); - if (!hasBidi) { - for (int i = 0; i < length; ++i) { - if (text[i].unicode() >= 0x590) { - hasBidi = true; + if (baseLevel != 0) + return true; + for (int i = 0; i < length; ++i) { + if (text[i].unicode() >= 0x590) { + switch (text[i].direction()) { + case QChar::DirR: case QChar::DirAN: + case QChar::DirLRE: case QChar::DirLRO: case QChar::DirAL: + case QChar::DirRLE: case QChar::DirRLO: case QChar::DirPDF: + case QChar::DirLRI: case QChar::DirRLI: case QChar::DirFSI: case QChar::DirPDI: + return true; + default: break; } } } + return false; + } + + bool process() + { + memset(analysis, 0, length * sizeof(QScriptAnalysis)); + + bool hasBidi = checkForBidi(); if (!hasBidi) return false; @@ -2071,7 +2083,6 @@ void QTextEngine::itemize() const case QChar::Nbsp: if (option.flags() & QTextOption::ShowTabsAndSpaces) { analysis->flags = (*uc == QChar::Space) ? QScriptAnalysis::Space : QScriptAnalysis::Nbsp; - analysis->bidiLevel = bidi.baseLevel; break; } Q_FALLTHROUGH(); diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index bba7d044f7..e29e5b8187 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -378,6 +378,11 @@ void QWindowsContext::setTabletAbsoluteRange(int a) #endif } +void QWindowsContext::setDetectAltGrModifier(bool a) +{ + d->m_keyMapper.setDetectAltGrModifier(a); +} + int QWindowsContext::processDpiAwareness() { int result; diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index fe83c83934..3709d9deee 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -208,6 +208,8 @@ public: void setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness); static int processDpiAwareness(); + void setDetectAltGrModifier(bool a); + // Returns a combination of SystemInfoFlags unsigned systemInfo() const; diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 1a1d51cae1..4824de5c9c 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -198,6 +198,8 @@ static inline unsigned parseOptions(const QStringList ¶mList, } else if (param.endsWith(QLatin1String("none"))) { options |= QWindowsIntegration::NoNativeDialogs; } + } else if (param == QLatin1String("altgr")) { + options |= QWindowsIntegration::DetectAltGrModifier; } else if (param == QLatin1String("gl=gdi")) { options |= QWindowsIntegration::DisableArb; } else if (param == QLatin1String("nodirectwrite")) { @@ -269,6 +271,7 @@ QWindowsIntegration::QWindowsIntegration(const QStringList ¶mList) : d->m_clipboard.registerViewer(); #endif d->m_context.screenManager().handleScreenChanges(); + d->m_context.setDetectAltGrModifier((d->m_options & DetectAltGrModifier) != 0); } QWindowsIntegration::~QWindowsIntegration() diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index 25f485679d..da86852766 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -69,6 +69,7 @@ public: AlwaysUseNativeMenus = 0x100, NoNativeMenus = 0x200, DontUseWMPointer = 0x400, + DetectAltGrModifier = 0x800 }; explicit QWindowsIntegration(const QStringList ¶mList); diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index e7efd6e057..1209b6c4b4 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -672,6 +672,7 @@ void QWindowsKeyMapper::changeKeyboard() bidi = true; keyboardInputDirection = bidi ? Qt::RightToLeft : Qt::LeftToRight; + m_seenAltGr = false; } // Helper function that is used when obtaining the list of characters that can be produced by one key and @@ -906,8 +907,34 @@ bool QWindowsKeyMapper::translateMultimediaKeyEventInternal(QWindow *window, con #endif } -bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &msg, bool /* grab */, LRESULT *lResult) +// QTBUG-69317: Check for AltGr found on some keyboards +// which is a sequence of left Ctrl (SYSKEY) + right Menu (Alt). +static bool isAltGr(MSG *msg) { + enum : LONG_PTR { RightFlag = 0x1000000 }; + if (msg->wParam != VK_CONTROL || (msg->lParam & RightFlag) != 0 + || (msg->message != WM_KEYDOWN && msg->message != WM_SYSKEYUP)) { + return false; + } + const UINT expectedMessage = msg->message == WM_SYSKEYUP + ? WM_KEYUP : msg->message; + MSG peekedMsg; + if (PeekMessage(&peekedMsg, msg->hwnd, 0, 0, PM_NOREMOVE) == FALSE + || peekedMsg.message != expectedMessage || peekedMsg.wParam != VK_MENU + || (peekedMsg.lParam & RightFlag) == 0) { + return false; + } + *msg = peekedMsg; + PeekMessage(&peekedMsg, msg->hwnd, 0, 0, PM_REMOVE); + return true; +} + +bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg, + bool /* grab */, LRESULT *lResult) +{ + const bool altGr = m_detectAltGrModifier && isAltGr(&msg); + if (altGr) + m_seenAltGr = true; const UINT msgType = msg.message; const quint32 scancode = (msg.lParam >> 16) & scancodeBitmask; @@ -936,10 +963,12 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms // Get the modifier states (may be altered later, depending on key code) int state = 0; state |= (nModifiers & ShiftAny ? int(Qt::ShiftModifier) : 0); - state |= (nModifiers & ControlAny ? int(Qt::ControlModifier) : 0); - state |= (nModifiers & AltAny ? int(Qt::AltModifier) : 0); + state |= (nModifiers & AltLeft ? int(Qt::AltModifier) : 0); + if ((nModifiers & AltRight) != 0) + state |= m_seenAltGr ? Qt::GroupSwitchModifier : Qt::AltModifier; + if ((nModifiers & ControlAny) != 0 && (state & Qt::GroupSwitchModifier) == 0) + state |= Qt::ControlModifier; state |= (nModifiers & MetaAny ? int(Qt::MetaModifier) : 0); - // A multi-character key or a Input method character // not found by our look-ahead if (msgType == WM_CHAR || msgType == WM_IME_CHAR) { @@ -1010,8 +1039,17 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms modifiersIndex |= (nModifiers & ControlAny ? 0x2 : 0); modifiersIndex |= (nModifiers & AltAny ? 0x4 : 0); + // Note: For the resulting key, AltGr is equivalent to Alt + Ctrl (as + // opposed to Linux); hence no entry in KeyboardLayoutItem is required int code = keyLayout[vk_key].qtKey[modifiersIndex]; + // If the bit 24 of lParm is set you received a enter, + // otherwise a Return. (This is the extended key bit) + if ((code == Qt::Key_Return) && (msg.lParam & 0x1000000)) + code = Qt::Key_Enter; + else if (altGr) + code = Qt::Key_AltGr; + // Invert state logic: // If the key actually pressed is a modifier key, then we remove its modifier key from the // state, since a modifier-key can't have itself as a modifier @@ -1021,11 +1059,8 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms state = state ^ Qt::ShiftModifier; else if (code == Qt::Key_Alt) state = state ^ Qt::AltModifier; - - // If the bit 24 of lParm is set you received a enter, - // otherwise a Return. (This is the extended key bit) - if ((code == Qt::Key_Return) && (msg.lParam & 0x1000000)) - code = Qt::Key_Enter; + else if (code == Qt::Key_AltGr) + state = state ^ Qt::GroupSwitchModifier; // All cursor keys without extended bit if (!(msg.lParam & 0x1000000)) { diff --git a/src/plugins/platforms/windows/qwindowskeymapper.h b/src/plugins/platforms/windows/qwindowskeymapper.h index d569c82437..a454f0f973 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.h +++ b/src/plugins/platforms/windows/qwindowskeymapper.h @@ -81,6 +81,9 @@ public: void setUseRTLExtensions(bool e) { m_useRTLExtensions = e; } bool useRTLExtensions() const { return m_useRTLExtensions; } + void setDetectAltGrModifier(bool a) { m_detectAltGrModifier = a; } + bool detectAltGrModifier() const { return m_detectAltGrModifier; } + bool translateKeyEvent(QWindow *widget, HWND hwnd, const MSG &msg, LRESULT *result); QWindow *keyGrabber() const { return m_keyGrabber; } @@ -90,7 +93,7 @@ public: QList<int> possibleKeys(const QKeyEvent *e) const; private: - bool translateKeyEventInternal(QWindow *receiver, const MSG &msg, bool grab, LRESULT *lResult); + bool translateKeyEventInternal(QWindow *receiver, MSG msg, bool grab, LRESULT *lResult); bool translateMultimediaKeyEventInternal(QWindow *receiver, const MSG &msg); void updateKeyMap(const MSG &msg); @@ -106,6 +109,9 @@ private: QChar m_lastHighSurrogate; static const size_t NumKeyboardLayoutItems = 256; KeyboardLayoutItem keyLayout[NumKeyboardLayoutItems]; + bool m_detectAltGrModifier = false; + bool m_seenAltGr = false; + }; enum WindowsNativeModifiers { diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp index c4ee820211..6af9f168a5 100644 --- a/src/plugins/platforms/windows/qwindowsopengltester.cpp +++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp @@ -60,6 +60,8 @@ QT_BEGIN_NAMESPACE +static const DWORD VENDOR_ID_AMD = 0x1002; + GpuDescription GpuDescription::detect() { typedef IDirect3D9 * (WINAPI *PtrDirect3DCreate9)(UINT); @@ -74,9 +76,16 @@ GpuDescription GpuDescription::detect() IDirect3D9 *direct3D9 = direct3DCreate9(D3D_SDK_VERSION); if (!direct3D9) return result; + D3DADAPTER_IDENTIFIER9 adapterIdentifier; - const HRESULT hr = direct3D9->GetAdapterIdentifier(0, 0, &adapterIdentifier); - direct3D9->Release(); + bool isAMD = false; + // Adapter "0" is D3DADAPTER_DEFAULT which returns the default adapter. In + // multi-GPU, multi-screen setups this is the GPU that is associated with + // the "main display" in the Display Settings, and this is the GPU OpenGL + // and D3D uses by default. Therefore querying any additional adapters is + // futile and not useful for our purposes in general, except for + // identifying a few special cases later on. + HRESULT hr = direct3D9->GetAdapterIdentifier(0, 0, &adapterIdentifier); if (SUCCEEDED(hr)) { result.vendorId = adapterIdentifier.VendorId; result.deviceId = adapterIdentifier.DeviceId; @@ -90,7 +99,37 @@ GpuDescription GpuDescription::detect() result.driverVersion = QVersionNumber(version); result.driverName = adapterIdentifier.Driver; result.description = adapterIdentifier.Description; + isAMD = result.vendorId == VENDOR_ID_AMD; } + + // Detect QTBUG-50371 (having AMD as the default adapter results in a crash + // when starting apps on a screen connected to the Intel card) by looking + // for a default AMD adapter and an additional non-AMD one. + if (isAMD) { + const UINT adapterCount = direct3D9->GetAdapterCount(); + for (UINT adp = 1; adp < adapterCount; ++adp) { + hr = direct3D9->GetAdapterIdentifier(adp, 0, &adapterIdentifier); + if (SUCCEEDED(hr)) { + if (adapterIdentifier.VendorId != VENDOR_ID_AMD) { + // Bingo. Now figure out the display for the AMD card. + DISPLAY_DEVICE dd; + memset(&dd, 0, sizeof(dd)); + dd.cb = sizeof(dd); + for (int dev = 0; EnumDisplayDevices(nullptr, dev, &dd, 0); ++dev) { + if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) { + // DeviceName is something like \\.\DISPLAY1 which can be used to + // match with the MONITORINFOEX::szDevice queried by QWindowsScreen. + result.gpuSuitableScreen = QString::fromWCharArray(dd.DeviceName); + break; + } + } + break; + } + } + } + } + + direct3D9->Release(); return result; } @@ -103,7 +142,8 @@ QDebug operator<<(QDebug d, const GpuDescription &gd) << ", deviceId=" << gd.deviceId << ", subSysId=" << gd.subSysId << dec << noshowbase << ", revision=" << gd.revision << ", driver: " << gd.driverName - << ", version=" << gd.driverVersion << ", " << gd.description << ')'; + << ", version=" << gd.driverVersion << ", " << gd.description + << gd.gpuSuitableScreen << ')'; return d; } #endif // !QT_NO_DEBUG_STREAM @@ -113,15 +153,17 @@ QString GpuDescription::toString() const { QString result; QTextStream str(&result); - str << " Card name: " << description - << "\n Driver Name: " << driverName - << "\n Driver Version: " << driverVersion.toString() - << "\n Vendor ID: 0x" << qSetPadChar(QLatin1Char('0')) + str << " Card name : " << description + << "\n Driver Name : " << driverName + << "\n Driver Version : " << driverVersion.toString() + << "\n Vendor ID : 0x" << qSetPadChar(QLatin1Char('0')) << uppercasedigits << hex << qSetFieldWidth(4) << vendorId - << "\n Device ID: 0x" << qSetFieldWidth(4) << deviceId - << "\n SubSys ID: 0x" << qSetFieldWidth(8) << subSysId - << "\n Revision ID: 0x" << qSetFieldWidth(4) << revision + << "\n Device ID : 0x" << qSetFieldWidth(4) << deviceId + << "\n SubSys ID : 0x" << qSetFieldWidth(8) << subSysId + << "\n Revision ID : 0x" << qSetFieldWidth(4) << revision << dec; + if (!gpuSuitableScreen.isEmpty()) + str << "\nGL windows forced to screen: " << gpuSuitableScreen; return result; } diff --git a/src/plugins/platforms/windows/qwindowsopengltester.h b/src/plugins/platforms/windows/qwindowsopengltester.h index 5ee2508462..22170f30b0 100644 --- a/src/plugins/platforms/windows/qwindowsopengltester.h +++ b/src/plugins/platforms/windows/qwindowsopengltester.h @@ -62,6 +62,7 @@ struct GpuDescription QVersionNumber driverVersion; QByteArray driverName; QByteArray description; + QString gpuSuitableScreen; }; #ifndef QT_NO_DEBUG_STREAM diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 528927b0fb..9c31409644 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -58,6 +58,7 @@ #else # include "qwindowsopenglcontext.h" #endif +#include "qwindowsopengltester.h" #ifdef QT_NO_CURSOR # include "qwindowscursor.h" #endif @@ -541,6 +542,84 @@ static inline void fixTopLevelWindowFlags(Qt::WindowFlags &flags) flags |= Qt::FramelessWindowHint; } +static QScreen *screenForName(const QWindow *w, const QString &name) +{ + QScreen *winScreen = w ? w->screen() : QGuiApplication::primaryScreen(); + if (winScreen && winScreen->name() != name) { + const auto screens = winScreen->virtualSiblings(); + for (QScreen *screen : screens) { + if (screen->name() == name) + return screen; + } + } + return winScreen; +} + +static QScreen *forcedScreenForGLWindow(const QWindow *w) +{ + const QString forceToScreen = GpuDescription::detect().gpuSuitableScreen; + return forceToScreen.isEmpty() ? nullptr : screenForName(w, forceToScreen); +} + +static QPoint calcPosition(const QWindow *w, const QWindowCreationContextPtr &context, const QMargins &invMargins) +{ + const QPoint orgPos(context->frameX - invMargins.left(), context->frameY - invMargins.top()); + + if (!w || (!w->isTopLevel() && w->surfaceType() != QWindow::OpenGLSurface)) + return orgPos; + + // Workaround for QTBUG-50371 + const QScreen *screenForGL = forcedScreenForGLWindow(w); + if (!screenForGL) + return orgPos; + + const QPoint posFrame(context->frameX, context->frameY); + const QMargins margins = context->margins; + const QRect scrGeo = screenForGL->handle()->availableGeometry(); + + // Point is already in the required screen. + if (scrGeo.contains(orgPos)) + return orgPos; + + // If the visible part of the window is already in the + // required screen, just ignore the invisible offset. + if (scrGeo.contains(posFrame)) + return posFrame; + + // Find the original screen containing the coordinates. + const QList<QScreen *> screens = screenForGL->virtualSiblings(); + const QScreen *orgScreen = nullptr; + for (QScreen *screen : screens) { + if (screen->handle()->availableGeometry().contains(posFrame)) { + orgScreen = screen; + break; + } + } + const QPoint ctPos = QPoint(qMax(scrGeo.left(), scrGeo.center().x() + + (margins.right() - margins.left() - context->frameWidth)/2), + qMax(scrGeo.top(), scrGeo.center().y() + + (margins.bottom() - margins.top() - context->frameHeight)/2)); + + // If initial coordinates were outside all screens, center the window on the required screen. + if (!orgScreen) + return ctPos; + + const QRect orgGeo = orgScreen->handle()->availableGeometry(); + const QRect orgFrame(QPoint(context->frameX, context->frameY), + QSize(context->frameWidth, context->frameHeight)); + + // Window would be centered on orgScreen. Center it on the required screen. + if (orgGeo.center() == (orgFrame - margins).center()) + return ctPos; + + // Transform the coordinates to map them into the required screen. + const QPoint newPos(scrGeo.left() + ((posFrame.x() - orgGeo.left()) * scrGeo.width()) / orgGeo.width(), + scrGeo.top() + ((posFrame.y() - orgGeo.top()) * scrGeo.height()) / orgGeo.height()); + const QPoint newPosNoMargin(newPos.x() - invMargins.left(), newPos.y() - invMargins.top()); + + return scrGeo.contains(newPosNoMargin) ? newPosNoMargin : newPos; +} + void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flagsIn, unsigned creationFlags) { @@ -688,9 +767,12 @@ QWindowsWindowData << " custom margins: " << context->customMargins << " invisible margins: " << invMargins; + + QPoint pos = calcPosition(w, context, invMargins); + result.hwnd = CreateWindowEx(exStyle, classNameUtf16, titleUtf16, style, - context->frameX - invMargins.left(), context->frameY - invMargins.top(), + pos.x(), pos.y(), context->frameWidth, context->frameHeight, parentHandle, NULL, appinst, NULL); qCDebug(lcQpaWindows).nospace() diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp index 11397fb9ec..7a91c3d4e2 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp @@ -180,7 +180,7 @@ long roleToControlTypeId(QAccessible::Role role) {QAccessible::PropertyPage, UIA_CustomControlTypeId}, {QAccessible::Indicator, UIA_CustomControlTypeId}, {QAccessible::Graphic, UIA_ImageControlTypeId}, - {QAccessible::StaticText, UIA_EditControlTypeId}, + {QAccessible::StaticText, UIA_TextControlTypeId}, {QAccessible::EditableText, UIA_EditControlTypeId}, {QAccessible::Button, UIA_ButtonControlTypeId}, {QAccessible::CheckBox, UIA_CheckBoxControlTypeId}, diff --git a/src/plugins/printsupport/cups/qcupsprintersupport.cpp b/src/plugins/printsupport/cups/qcupsprintersupport.cpp index 56191c4dec..19e1df31f6 100644 --- a/src/plugins/printsupport/cups/qcupsprintersupport.cpp +++ b/src/plugins/printsupport/cups/qcupsprintersupport.cpp @@ -47,12 +47,14 @@ #include <QtPrintSupport/QPrinterInfo> +#if QT_CONFIG(dialogbuttonbox) #include <QGuiApplication> #include <QDialog> #include <QDialogButtonBox> #include <QFormLayout> #include <QLabel> #include <QLineEdit> +#endif // QT_CONFIG(dialogbuttonbox) #include <cups/ppd.h> #ifndef QT_LINUXBASE // LSB merges everything into cups.h @@ -61,6 +63,7 @@ QT_BEGIN_NAMESPACE +#if QT_CONFIG(dialogbuttonbox) static const char *getPasswordCB(const char */*prompt*/, http_t *http, const char */*method*/, const char *resource, void */*user_data*/) { // cups doesn't free the const char * we return so keep around @@ -122,13 +125,16 @@ static const char *getPasswordCB(const char */*prompt*/, http_t *http, const cha return password.constData(); } +#endif // QT_CONFIG(dialogbuttonbox) QCupsPrinterSupport::QCupsPrinterSupport() : QPlatformPrinterSupport() { +#if QT_CONFIG(dialogbuttonbox) // Only show password dialog if GUI application if (qobject_cast<QGuiApplication*>(QCoreApplication::instance())) cupsSetPasswordCB2(getPasswordCB, nullptr /* user_data */ ); +#endif // QT_CONFIG(dialogbuttonbox) } QCupsPrinterSupport::~QCupsPrinterSupport() diff --git a/src/testlib/3rdparty/qt_attribution.json b/src/testlib/3rdparty/qt_attribution.json index 47625634e5..18522b6cd8 100644 --- a/src/testlib/3rdparty/qt_attribution.json +++ b/src/testlib/3rdparty/qt_attribution.json @@ -8,6 +8,7 @@ "Description": "An instrumentation framework for building dynamic analysis tools.", "Homepage": "http://valgrind.org/", + "Version": "3.3.0", "License": "BSD 4-clause \"Original\" or \"Old\" License", "LicenseId": "BSD-4-Clause", "LicenseFile": "VALGRIND_LICENSE.txt", @@ -36,6 +37,8 @@ Copyright (c) 2003, 2006 Massachusetts Institute of Technology" "Files": "linux_perf_event_p.h", "Description": "Allows access to the Linux kernel's performance events.", + "Homepage": "https://www.kernel.org", + "Version": "3.7", "License": "GNU General Public License v2.0 only with Linux Syscall Note", "LicenseId": "GPL-2.0 WITH Linux-syscall-note", "LicenseFile": "LINUX_LICENSE.txt", diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp index 29681bf5ce..3b78d2487f 100644 --- a/src/tools/androiddeployqt/main.cpp +++ b/src/tools/androiddeployqt/main.cpp @@ -95,6 +95,7 @@ struct Options , generateAssetsFileList(true) , build(true) , gradle(false) + , auxMode(false) , deploymentMechanism(Bundled) , releasePackage(false) , digestAlg(QLatin1String("SHA1")) @@ -126,6 +127,7 @@ struct Options bool generateAssetsFileList; bool build; bool gradle; + bool auxMode; QTime timer; // External tools @@ -432,6 +434,8 @@ Options parseOptions() options.jarSigner = true; } else if (argument.compare(QLatin1String("--no-generated-assets-cache"), Qt::CaseInsensitive) == 0) { options.generateAssetsFileList = false; + } else if (argument.compare(QLatin1String("--aux-mode"), Qt::CaseInsensitive) == 0) { + options.auxMode = true; } } @@ -517,6 +521,9 @@ void printHelp() " --verbose: Prints out information during processing.\n" " --no-generated-assets-cache: Do not pregenerate the entry list for\n" " the assets file engine.\n" + " --aux-mode: Operate in auxiliary mode. This will only copy the\n" + " dependencies into the build directory and update the XML templates.\n" + " The project will not be built or installed.\n" " --help: Displays this information.\n\n", qPrintable(QCoreApplication::arguments().at(0)) ); @@ -2826,6 +2833,22 @@ int main(int argc, char *argv[]) : "No" ); + if (options.auxMode) { + if (!readDependencies(&options)) + return CannotReadDependencies; + if (!copyQtFiles(&options)) + return CannotCopyQtFiles; + if (!copyAndroidExtraResources(options)) + return CannotCopyAndroidExtraResources; + if (!stripLibraries(options)) + return CannotStripLibraries; + if (!updateAndroidFiles(options)) + return CannotUpdateAndroidFiles; + if (options.generateAssetsFileList && !generateAssetsFileList(options)) + return CannotGenerateAssetsFileList; + return 0; + } + if (options.build) { if (options.gradle) cleanAndroidFiles(options); diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index 2742b152f2..9116bf61fe 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -1047,10 +1047,15 @@ void QFileDialog::selectFile(const QString &filename) return; if (!d->usingWidgets()) { - QUrl url = QUrl::fromLocalFile(filename); + QUrl url; if (QFileInfo(filename).isRelative()) { - QDir dir(d->options->initialDirectory().toLocalFile()); - url = QUrl::fromLocalFile(dir.absoluteFilePath(filename)); + url = d->options->initialDirectory(); + QString path = url.path(); + if (!path.endsWith(QLatin1Char('/'))) + path += QLatin1Char('/'); + url.setPath(path + filename); + } else { + url = QUrl::fromLocalFile(filename); } d->selectFile_sys(url); d->options->setInitiallySelectedFiles(QList<QUrl>() << url); diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 1c73588b7c..1a2ac4a4dd 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -977,7 +977,10 @@ void QWidgetWindow::handleExposeEvent(QExposeEvent *event) } if (exposed) { + // QTBUG-39220, QTBUG-58575: set all (potentially fully obscured parent widgets) mapped. m_widget->setAttribute(Qt::WA_Mapped); + for (QWidget *p = m_widget->parentWidget(); p && !p->testAttribute(Qt::WA_Mapped); p = p->parentWidget()) + p->setAttribute(Qt::WA_Mapped); if (!event->region().isNull()) wPriv->syncBackingStore(event->region()); } else { diff --git a/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.cpp b/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.cpp index 94c3fa6e46..646f96c3a1 100644 --- a/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.cpp +++ b/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.cpp @@ -4662,4 +4662,236 @@ void tst_QSortFilterProxyModel::checkSetNewModel() QCoreApplication::processEvents(); } +enum ColumnFilterMode { + FilterNothing, + FilterOutMiddle, + FilterOutBeginEnd, + FilterAll +}; +Q_DECLARE_METATYPE(ColumnFilterMode) + +void tst_QSortFilterProxyModel::filterAndInsertColumn_data() +{ + + QTest::addColumn<int>("insertCol"); + QTest::addColumn<ColumnFilterMode>("filterMode"); + QTest::addColumn<QStringList>("expectedModelList"); + QTest::addColumn<QStringList>("expectedProxyModelList"); + + QTest::newRow("at_beginning_filter_out_middle") + << 0 + << FilterOutMiddle + << QStringList{{"", "A1", "B1", "C1", "D1"}} + << QStringList{{"", "D1"}} + ; + QTest::newRow("at_end_filter_out_middle") + << 2 + << FilterOutMiddle + << QStringList{{"A1", "B1", "C1", "D1", ""}} + << QStringList{{"A1", ""}} + ; + QTest::newRow("in_the_middle_filter_out_middle") + << 1 + << FilterOutMiddle + << QStringList{{"A1", "B1", "C1", "", "D1"}} + << QStringList{{"A1", "D1"}} + ; + QTest::newRow("at_beginning_filter_out_begin_and_end") + << 0 + << FilterOutBeginEnd + << QStringList{{"A1", "", "B1", "C1", "D1"}} + << QStringList{{"", "B1", "C1"}} + ; + QTest::newRow("at_end_filter_out_begin_and_end") + << 2 + << FilterOutBeginEnd + << QStringList{{"A1", "B1", "C1", "D1", ""}} + << QStringList{{"B1", "C1", "D1"}} + ; + QTest::newRow("in_the_middle_filter_out_begin_and_end") + << 1 + << FilterOutBeginEnd + << QStringList{{"A1", "B1", "", "C1", "D1"}} + << QStringList{{"B1", "", "C1"}} + ; + + QTest::newRow("at_beginning_filter_nothing") + << 0 + << FilterAll + << QStringList{{"", "A1", "B1", "C1", "D1"}} + << QStringList{{"", "A1", "B1", "C1", "D1"}} + ; + QTest::newRow("at_end_filter_nothing") + << 4 + << FilterAll + << QStringList{{"A1", "B1", "C1", "D1", ""}} + << QStringList{{"A1", "B1", "C1", "D1", ""}} + ; + QTest::newRow("in_the_middle_nothing") + << 2 + << FilterAll + << QStringList{{"A1", "B1", "", "C1", "D1"}} + << QStringList{{"A1", "B1", "", "C1", "D1"}} + ; + + QTest::newRow("filter_all") + << 0 + << FilterNothing + << QStringList{{"A1", "B1", "C1", "D1", ""}} + << QStringList{} + ; +} +void tst_QSortFilterProxyModel::filterAndInsertColumn() +{ + + class ColumnFilterProxy : public QSortFilterProxyModel { + Q_DISABLE_COPY(ColumnFilterProxy) + ColumnFilterMode filerMode; + public: + ColumnFilterProxy(ColumnFilterMode mode) + : filerMode(mode) + {} + bool filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const override + { + Q_UNUSED(source_parent) + switch (filerMode){ + case FilterAll: + return true; + case FilterNothing: + return false; + case FilterOutMiddle: + return source_column == 0 || source_column == sourceModel()->columnCount() - 1; + case FilterOutBeginEnd: + return source_column > 0 && source_column< sourceModel()->columnCount() - 1; + } + Q_UNREACHABLE(); + } + }; + QFETCH(int, insertCol); + QFETCH(ColumnFilterMode, filterMode); + QFETCH(QStringList, expectedModelList); + QFETCH(QStringList, expectedProxyModelList); + QStandardItemModel model; + model.insertColumns(0, 4); + model.insertRows(0, 1); + for (int i = 0; i < model.rowCount(); ++i) { + for (int j = 0; j < model.columnCount(); ++j) + model.setData(model.index(i, j), QString('A' + j) + QString::number(i + 1)); + } + ColumnFilterProxy proxy(filterMode); + proxy.setSourceModel(&model); + QVERIFY(proxy.insertColumn(insertCol)); + proxy.invalidate(); + QStringList modelStringList; + for (int i = 0; i < model.rowCount(); ++i) { + for (int j = 0; j < model.columnCount(); ++j) + modelStringList.append(model.index(i, j).data().toString()); + } + QCOMPARE(expectedModelList, modelStringList); + modelStringList.clear(); + for (int i = 0; i < proxy.rowCount(); ++i) { + for (int j = 0; j < proxy.columnCount(); ++j) + modelStringList.append(proxy.index(i, j).data().toString()); + } + QCOMPARE(expectedProxyModelList, modelStringList); +} + +void tst_QSortFilterProxyModel::filterAndInsertRow_data() +{ + QTest::addColumn<QStringList>("initialModelList"); + QTest::addColumn<int>("row"); + QTest::addColumn<QString>("filterRegExp"); + QTest::addColumn<QStringList>("expectedModelList"); + QTest::addColumn<QStringList>("expectedProxyModelList"); + + QTest::newRow("at_beginning_filter_out_middle") + << QStringList{{"A5", "B5", "B6", "A7"}} + << 0 + << "^A" + << QStringList{{"", "A5", "B5", "B6", "A7"}} + << QStringList{{"A5", "A7"}}; + QTest::newRow("at_end_filter_out_middle") + << QStringList{{"A5", "B5", "B6", "A7"}} + << 2 + << "^A" + << QStringList{{"A5", "B5", "B6", "A7", ""}} + << QStringList{{"A5", "A7"}}; + QTest::newRow("in_the_middle_filter_out_middle") + << QStringList{{"A5", "B5", "B6", "A7"}} + << 1 + << "^A" + << QStringList{{"A5", "B5", "B6", "", "A7"}} + << QStringList{{"A5", "A7"}}; + + QTest::newRow("at_beginning_filter_out_first_and_last") + << QStringList{{"A5", "B5", "B6", "A7"}} + << 0 + << "^B" + << QStringList{{"A5", "", "B5", "B6", "A7"}} + << QStringList{{"B5", "B6"}}; + QTest::newRow("at_end_filter_out_first_and_last") + << QStringList{{"A5", "B5", "B6", "A7"}} + << 2 + << "^B" + << QStringList{{"A5", "B5", "B6", "A7", ""}} + << QStringList{{"B5", "B6"}}; + QTest::newRow("in_the_middle_filter_out_first_and_last") + << QStringList{{"A5", "B5", "B6", "A7"}} + << 1 + << "^B" + << QStringList{{"A5", "B5", "", "B6", "A7"}} + << QStringList{{"B5", "B6"}}; + + QTest::newRow("at_beginning_no_filter") + << QStringList{{"A5", "B5", "B6", "A7"}} + << 0 + << ".*" + << QStringList{{"", "A5", "B5", "B6", "A7"}} + << QStringList{{"", "A5", "B5", "B6", "A7"}}; + QTest::newRow("at_end_no_filter") + << QStringList{{"A5", "B5", "B6", "A7"}} + << 4 + << ".*" + << QStringList{{"A5", "B5", "B6", "A7", ""}} + << QStringList{{"A5", "B5", "B6", "A7", ""}}; + QTest::newRow("in_the_middle_no_filter") + << QStringList{{"A5", "B5", "B6", "A7"}} + << 2 + << ".*" + << QStringList{{"A5", "B5", "", "B6", "A7"}} + << QStringList{{"A5", "B5", "", "B6", "A7"}}; + + QTest::newRow("filter_all") + << QStringList{{"A5", "B5", "B6", "A7"}} + << 0 + << "$a" + << QStringList{{"A5", "B5", "B6", "A7", ""}} + << QStringList{}; +} + +void tst_QSortFilterProxyModel::filterAndInsertRow() +{ + QFETCH(QStringList, initialModelList); + QFETCH(int, row); + QFETCH(QString, filterRegExp); + QFETCH(QStringList, expectedModelList); + QFETCH(QStringList, expectedProxyModelList); + QStringListModel model; + QSortFilterProxyModel proxyModel; + + model.setStringList(initialModelList); + proxyModel.setSourceModel(&model); + proxyModel.setDynamicSortFilter(true); + proxyModel.setFilterRegExp(filterRegExp); + + QVERIFY(proxyModel.insertRow(row)); + QCOMPARE(model.stringList(), expectedModelList); + QCOMPARE(proxyModel.rowCount(), expectedProxyModelList.count()); + for (int r = 0; r < proxyModel.rowCount(); ++r) { + QModelIndex index = proxyModel.index(r, 0); + QVERIFY(index.isValid()); + QCOMPARE(proxyModel.data(index).toString(), expectedProxyModelList.at(r)); + } +} + #include "tst_qsortfilterproxymodel.moc" diff --git a/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.h b/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.h index 92f0b35065..4ea5e8fb6a 100644 --- a/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.h +++ b/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.h @@ -161,6 +161,10 @@ private slots: void emitLayoutChangedOnlyIfSortingChanged(); void checkSetNewModel(); + void filterAndInsertRow_data(); + void filterAndInsertRow(); + void filterAndInsertColumn_data(); + void filterAndInsertColumn(); void removeIntervals_data(); void removeIntervals(); diff --git a/tests/auto/corelib/kernel/qeventdispatcher/BLACKLIST b/tests/auto/corelib/kernel/qeventdispatcher/BLACKLIST index 402d87b82f..fb7e025b7c 100644 --- a/tests/auto/corelib/kernel/qeventdispatcher/BLACKLIST +++ b/tests/auto/corelib/kernel/qeventdispatcher/BLACKLIST @@ -4,3 +4,4 @@ osx [registerTimer] windows osx +winrt diff --git a/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp b/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp index 79309f960d..0196dd2d23 100644 --- a/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp +++ b/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp @@ -423,7 +423,12 @@ void tst_QEasingCurve::setCustomType() QCOMPARE(curve.valueForProgress(0.15), 0.1); QCOMPARE(curve.valueForProgress(0.20), 0.2); QCOMPARE(curve.valueForProgress(0.25), 0.2); + // QTBUG-69947, MinGW 7.3 returns 0.2 +#if defined(Q_CC_MINGW) +#if !defined(__GNUC__) || __GNUC__ != 7 || __GNUC_MINOR__ < 3 QCOMPARE(curve.valueForProgress(0.30), 0.3); +#endif +#endif QCOMPARE(curve.valueForProgress(0.35), 0.3); QCOMPARE(curve.valueForProgress(0.999999), 0.9); diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp index 08aa00df56..5ffd75f931 100644 --- a/tests/auto/gui/image/qimage/tst_qimage.cpp +++ b/tests/auto/gui/image/qimage/tst_qimage.cpp @@ -120,6 +120,7 @@ private slots: void smoothScale2(); void smoothScale3_data(); void smoothScale3(); + void smoothScale4_data(); void smoothScale4(); void smoothScaleBig(); @@ -1681,29 +1682,30 @@ void tst_QImage::smoothScale() // test area sampling void tst_QImage::smoothScale2_data() { - QTest::addColumn<int>("format"); + QTest::addColumn<QImage::Format>("format"); QTest::addColumn<int>("size"); int sizes[] = { 2, 3, 4, 6, 7, 8, 10, 16, 20, 32, 40, 64, 100, 101, 128, 0 }; - QImage::Format formats[] = { QImage::Format_RGB32, QImage::Format_ARGB32_Premultiplied, QImage::Format_Invalid }; + QImage::Format formats[] = { QImage::Format_RGB32, QImage::Format_ARGB32_Premultiplied, QImage::Format_RGBX64, QImage::Format_RGBA64_Premultiplied, QImage::Format_Invalid }; for (int j = 0; formats[j] != QImage::Format_Invalid; ++j) { - QByteArray formatstr = formats[j] == QImage::Format_RGB32 ? QByteArrayLiteral("rgb32") : QByteArrayLiteral("argb32pm"); + QString formatstr = formatToString(formats[j]); for (int i = 0; sizes[i] != 0; ++i) { const QByteArray sizeB = QByteArray::number(sizes[i]); - QTest::newRow((formatstr + ' ' + sizeB + 'x' + sizeB).constData()) - << (int)formats[j] << sizes[i]; + QTest::newRow(QString("%1 %2x%2").arg(formatstr).arg(sizes[i]).toUtf8()) << formats[j] << sizes[i]; } } } void tst_QImage::smoothScale2() { - QFETCH(int, format); + QFETCH(QImage::Format, format); QFETCH(int, size); - QRgb expected = format == QImage::Format_RGB32 ? qRgb(63, 127, 255) : qRgba(31, 63, 127, 127); + bool opaque = (format == QImage::Format_RGB32 || format == QImage::Format_RGBX64); + + QRgb expected = opaque ? qRgb(63, 127, 255) : qRgba(31, 63, 127, 127); - QImage img(size, size, (QImage::Format)format); + QImage img(size, size, format); img.fill(expected); // scale x down, y down @@ -1840,21 +1842,31 @@ void tst_QImage::smoothScale3() } // Tests smooth upscale is smooth +void tst_QImage::smoothScale4_data() +{ + QTest::addColumn<QImage::Format>("format"); + + QTest::newRow("RGB32") << QImage::Format_RGB32; + QTest::newRow("RGBx64") << QImage::Format_RGBX64; +} + void tst_QImage::smoothScale4() { - QImage img(4, 4, QImage::Format_RGB32); + QFETCH(QImage::Format, format); + QImage img(4, 4, format); for (int y = 0; y < 4; ++y) { for (int x = 0; x < 4; ++x) { img.setPixel(x, y, qRgb(x * 255 / 3, y * 255 / 3, 0)); } } QImage scaled = img.scaled(37, 23, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + QCOMPARE(scaled.format(), format); for (int y = 0; y < scaled.height(); ++y) { for (int x = 0; x < scaled.width(); ++x) { if (x > 0) - QVERIFY(qRed(scaled.pixel(x, y)) >= qRed(scaled.pixel(x - 1, y))); + QVERIFY(scaled.pixelColor(x, y).redF() >= scaled.pixelColor(x - 1, y).redF()); if (y > 0) - QVERIFY(qGreen(scaled.pixel(x, y)) >= qGreen(scaled.pixel(x, y - 1))); + QVERIFY(scaled.pixelColor(x, y).greenF() >= scaled.pixelColor(x, y - 1).greenF()); } } } diff --git a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp index a593deb90e..8b24937079 100644 --- a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp @@ -3882,7 +3882,7 @@ void tst_QAccessibility::bridgeTest() // Label hr = nodeList.at(4)->get_CurrentControlType(&controlTypeId); QVERIFY(SUCCEEDED(hr)); - QCOMPARE(controlTypeId, UIA_EditControlTypeId); + QCOMPARE(controlTypeId, UIA_TextControlTypeId); for (auto nd : nodeList) { nd->Release(); diff --git a/tests/auto/widgets/dialogs/qdialog/BLACKLIST b/tests/auto/widgets/dialogs/qdialog/BLACKLIST index 3da7337784..dd6a8bfff9 100644 --- a/tests/auto/widgets/dialogs/qdialog/BLACKLIST +++ b/tests/auto/widgets/dialogs/qdialog/BLACKLIST @@ -1,2 +1,4 @@ [snapToDefaultButton] osx +[showFullScreen] +osx-10.13 ci diff --git a/tests/auto/widgets/kernel/qwidget/BLACKLIST b/tests/auto/widgets/kernel/qwidget/BLACKLIST index 0f207b421e..2be016e99b 100644 --- a/tests/auto/widgets/kernel/qwidget/BLACKLIST +++ b/tests/auto/widgets/kernel/qwidget/BLACKLIST @@ -35,7 +35,7 @@ osx-10.11 ci osx-10.12 ci osx-10.13 ci [maskedUpdate] -opensuse-42.3 +opensuse [moveInResizeEvent] ubuntu-16.04 [moveChild:right] diff --git a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp index 2da04397d0..f4da4c3e5f 100644 --- a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp +++ b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp @@ -44,6 +44,8 @@ #include <qmainwindow.h> #include <qtoolbar.h> #include <private/qwindow_p.h> +#include <private/qguiapplication_p.h> +#include <qpa/qplatformintegration.h> #include <QtTest/private/qtesthelpers_p.h> @@ -79,6 +81,7 @@ private slots: void tst_showWithoutActivating(); void tst_paintEventOnSecondShow(); + void tst_exposeObscuredMapped_QTBUG39220(); void tst_paintEventOnResize_QTBUG50796(); #if QT_CONFIG(draganddrop) @@ -377,6 +380,33 @@ void tst_QWidget_window::tst_paintEventOnSecondShow() QTRY_VERIFY(w.paintEventCount > 0); } +void tst_QWidget_window::tst_exposeObscuredMapped_QTBUG39220() +{ + const auto integration = QGuiApplicationPrivate::platformIntegration(); + if (!integration->hasCapability(QPlatformIntegration::MultipleWindows) + || !integration->hasCapability(QPlatformIntegration::NonFullScreenWindows) + || QGuiApplication::platformName() == QLatin1String("winrt")) { + QSKIP("The platform does not have the required capabilities"); + } + // QTBUG-39220: Fully obscured parent widgets may not receive expose + // events (as is the case for frameless, obscured parents on Windows). + // Ensure Qt::WA_Mapped is set so updating works. + const QRect availableGeometry = QGuiApplication::primaryScreen()->availableGeometry(); + const QSize size = availableGeometry.size() / 6; + QWidget topLevel; + setFrameless(&topLevel); + topLevel.resize(size); + const QPoint sizeP(size.width(), size.height()); + topLevel.move(availableGeometry.center() - sizeP / 2); + QWidget *child = new QWidget(&topLevel); + child->resize(size); + child->move(0, 0); + QVERIFY(child->winId()); + topLevel.show(); + QTRY_VERIFY(child->testAttribute(Qt::WA_Mapped)); + QVERIFY(topLevel.testAttribute(Qt::WA_Mapped)); +} + void tst_QWidget_window::tst_paintEventOnResize_QTBUG50796() { const QRect availableGeo = QGuiApplication::primaryScreen()->availableGeometry(); |