From 70ba75519d66243b6fef6d452e9e158f7d3ea438 Mon Sep 17 00:00:00 2001 From: Luca Beldi Date: Fri, 17 Aug 2018 09:04:17 +0100 Subject: [PATCH 01/27] QSortFilterProxyModel inserting at bottom of source model Before this change, if you try to insert a row at the bottom of QSortFilterProxyModel the row will be inserted in the source model at position proxy->rowCount rather than at the bottom. This causes insert at apparently random positions in the source. [ChangeLog][QtCore][QSortFilterProxyModel] QSortFilterProxyModel::insertRows(row,count,parent) with row == QSortFilterProxyModel::rowCount will insert at the bottom of the source model rather than at the row QSortFilterProxyModel::rowCount of the source model Task-number: QTBUG-58499 Task-number: QTBUG-69158 Change-Id: Ie78416c8fbc429303b8c9c98375630e3e4d85f6d Reviewed-by: David Faure --- .../itemmodels/qsortfilterproxymodel.cpp | 4 +- .../tst_qsortfilterproxymodel.cpp | 237 ++++++++++++++++++ 2 files changed, 239 insertions(+), 2 deletions(-) diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/src/corelib/itemmodels/qsortfilterproxymodel.cpp index 08279cb244..6728f0106b 100644 --- a/src/corelib/itemmodels/qsortfilterproxymodel.cpp +++ b/src/corelib/itemmodels/qsortfilterproxymodel.cpp @@ -2191,7 +2191,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); } @@ -2211,7 +2211,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/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp index 947c4e8112..bced3f5790 100644 --- a/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp +++ b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp @@ -152,6 +152,11 @@ private slots: void emitLayoutChangedOnlyIfSortingChanged(); void checkSetNewModel(); + void filterAndInsertRow_data(); + void filterAndInsertRow(); + void filterAndInsertColumn_data(); + void filterAndInsertColumn(); + protected: void buildHierarchy(const QStringList &data, QAbstractItemModel *model); void checkHierarchy(const QStringList &data, const QAbstractItemModel *model); @@ -4612,5 +4617,237 @@ void tst_QSortFilterProxyModel::checkSetNewModel() QCoreApplication::processEvents(); } +enum ColumnFilterMode { + FilterNothing, + FilterOutMiddle, + FilterOutBeginEnd, + FilterAll +}; +Q_DECLARE_METATYPE(ColumnFilterMode) + +void tst_QSortFilterProxyModel::filterAndInsertColumn_data() +{ + + QTest::addColumn("insertCol"); + QTest::addColumn("filterMode"); + QTest::addColumn("expectedModelList"); + QTest::addColumn("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("initialModelList"); + QTest::addColumn("row"); + QTest::addColumn("filterRegExp"); + QTest::addColumn("expectedModelList"); + QTest::addColumn("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)); + } +} + QTEST_MAIN(tst_QSortFilterProxyModel) #include "tst_qsortfilterproxymodel.moc" From 1702ae24b3a35e370f0766d392f7bb273ddbd032 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 10 Aug 2018 14:46:49 +0200 Subject: [PATCH 02/27] Only show the bidi cursor mark if we actually have bidirectional text Don't show the mark simply because we have unicode code points larger than 0x590. Task-number: QTBUG-69665 Change-Id: I9af97383f3bcd52277a5288e7ad06ec240c7e51c Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/text/qtextengine.cpp | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 6751c077ac..5094ed9f52 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1037,19 +1037,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; From 055ff7a8a4da0eae4eacd38a911a3c1e3d56ea7b Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 10 Aug 2018 14:54:57 +0200 Subject: [PATCH 03/27] Don't reset the bidi level on spaces Fixes a regression introduced with the update to the bidi algorithm. Task-number: QTBUG-69633 Change-Id: I7eac45ed3ffb41f89ea3f793eedcfb6fcdace871 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/text/qtextengine.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 5094ed9f52..87dc63d59c 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -2077,7 +2077,6 @@ void QTextEngine::itemize() const case QChar::Nbsp: if (option.flags() & QTextOption::ShowTabsAndSpaces) { analysis->flags = QScriptAnalysis::Space; - analysis->bidiLevel = bidi.baseLevel; break; } Q_FALLTHROUGH(); From 981b16d9ba5a4bb7c6fdc0009fda9a4a74a92f9a Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Thu, 16 Aug 2018 15:55:10 +0200 Subject: [PATCH 04/27] Windows QPA: Fix mapping of static text accessibility role QAccessible::StaticText should be mapped to UIA_TextControlTypeId instead of UIA_EditControlTypeId. Task-number: QTBUG-69894 Change-Id: If2f8f55d2be492c02a3af5b1813ca12cf774a33a Reviewed-by: Oliver Wolff --- src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp | 2 +- tests/auto/other/qaccessibility/tst_qaccessibility.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp index f777a59ce9..294eed7701 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/tests/auto/other/qaccessibility/tst_qaccessibility.cpp b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp index b5d45adadb..8cf039c06a 100644 --- a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp @@ -3878,7 +3878,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(); From 54d062160d3a3d1c282cd19b57770611db3ea8eb Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 15 Aug 2018 16:07:25 +0200 Subject: [PATCH 05/27] Document version of copied valgrind, kernel headers Task-number: QTBUG-69276 Change-Id: If2d5d796fd9d414a41036187a178d88c2e93b5ff Reviewed-by: Thiago Macieira --- src/testlib/3rdparty/qt_attribution.json | 3 +++ 1 file changed, 3 insertions(+) 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", From 4932cef5b84d782f51ae7c6f77e09555bceacfee Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 8 Aug 2018 11:43:53 +0200 Subject: [PATCH 06/27] Cast away -Wclass-memaccess warnings in QVarLengthArray methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With g++ 8.2.0, I get warnings when a QVarLengthArray calls remove() or prepend(), as some tests in tst_QVarLengthArray do, as they call memmove() "writing to an object of type ‘class QString’ with no trivial copy-assignment; use copy-assignment or copy-initialization instead"; which may indeed be a good argument for not using QVarLengthArray, but its own tests do. Change-Id: I4f8a64948b32a54e67a285df4ec7788f60739ffb Reviewed-by: Thiago Macieira --- src/corelib/tools/qvarlengtharray.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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::iterator QVarLengthA } } else { T *b = ptr + offset; - memmove(b + 1, b, (s - offset) * sizeof(T)); + memmove(static_cast(b + 1), static_cast(b), (s - offset) * sizeof(T)); new (b) T(std::move(t)); } s += 1; @@ -518,7 +518,7 @@ Q_OUTOFLINE_TEMPLATE typename QVarLengthArray::iterator QVarLengthA } else { T *b = ptr + offset; T *i = b + n; - memmove(i, b, (s - offset - n) * sizeof(T)); + memmove(static_cast(i), static_cast(b), (s - offset - n) * sizeof(T)); while (i != b) new (--i) T(copy); } @@ -544,7 +544,7 @@ Q_OUTOFLINE_TEMPLATE typename QVarLengthArray::iterator QVarLengthA i->~T(); } } else { - memmove(ptr + f, ptr + l, (s - l) * sizeof(T)); + memmove(static_cast(ptr + f), static_cast(ptr + l), (s - l) * sizeof(T)); } s -= n; return ptr + f; From 2a9223830cd56fa1623d42d939df497eb20001af Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Tue, 14 Aug 2018 12:40:07 +0200 Subject: [PATCH 07/27] Doc: Remove duplicate thread-safe documentation from logging macros qdoc now handles \threadsafe also for macros, so we can remove the explicit \note. Change-Id: Iabeb7f69d237e7024a4f584adc516951b06d752b Reviewed-by: Leena Miettinen --- src/corelib/io/qloggingcategory.cpp | 16 ---------------- 1 file changed, 16 deletions(-) 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() */ /*! From 2d3098f77c98a895dad2c2e6c1c3facf712473f5 Mon Sep 17 00:00:00 2001 From: Alexander Shevchenko Date: Sun, 19 Aug 2018 15:44:24 +0300 Subject: [PATCH 08/27] Fix qtbase build for Windows ICC with MSVC 2017 15.8 After 0ef66e98ccf was merged, the same should be done to Windows ICC toolchain. Task-number: QTBUG-69997 Change-Id: I1d76d8b59f87151a9064d9f7dcc3136dc1215633 Reviewed-by: Thiago Macieira --- mkspecs/win32-icc/qmake.conf | 1 + 1 file changed, 1 insertion(+) 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 From d3dc3e774392007e2f679df6b08b75e35a8c7c44 Mon Sep 17 00:00:00 2001 From: Heikki Halmet Date: Thu, 16 Aug 2018 08:38:14 +0300 Subject: [PATCH 09/27] Extend blacklisting of qeventdispatcher to cover WinRT They have been blacklisted on windows and macOS previously. Now failing on WinRT as well. Task-number: QTBUG-69962 Change-Id: I30ca23005b082e820ee896fa36a8984a1536ad6b Reviewed-by: Oliver Wolff --- tests/auto/corelib/kernel/qeventdispatcher/BLACKLIST | 1 + 1 file changed, 1 insertion(+) 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 From 81d6cf71cc9202374a706305402a34dd1a06c2bd Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 13 Jul 2018 08:21:31 +0200 Subject: [PATCH 10/27] Windows QPA: Add option to detect AltGr key presses According to MSDN, AltGr key presses are sent as a sequence of SYS left Ctrl + right Alt. Add an option to detect AltGr as modifier key. Task-number: QTBUG-69317 Change-Id: I30ce169d2e6dbbae194ff714abfbc732b53652ce Reviewed-by: Oliver Wolff --- src/corelib/global/qnamespace.qdoc | 3 +- src/gui/kernel/qguiapplication.cpp | 3 ++ .../platforms/windows/qwindowscontext.cpp | 5 ++ .../platforms/windows/qwindowscontext.h | 2 + .../platforms/windows/qwindowsintegration.cpp | 3 ++ .../platforms/windows/qwindowsintegration.h | 1 + .../platforms/windows/qwindowskeymapper.cpp | 53 +++++++++++++++---- .../platforms/windows/qwindowskeymapper.h | 8 ++- 8 files changed, 67 insertions(+), 11 deletions(-) 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/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/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 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 { From 65b95b61d67f7802ea27f2965c62ac69808b32a0 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 20 Aug 2018 12:26:14 +0200 Subject: [PATCH 11/27] MinGW: Exclude failing value of tst_QEasingCurve::setCustomType() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After updating MinGW toolchain from 5.3.0 to 7.30 test starts to fail. Task-number: QTBUG-69947 Change-Id: I850d854b27e1cb4e1dd2cb600e8e79bd18bff4a0 Reviewed-by: Oliver Wolff Reviewed-by: Simo Fält --- tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp | 5 +++++ 1 file changed, 5 insertions(+) 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); From 5be5b798b2c4260a5baa6ceb920e6bdd676a7013 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 20 Aug 2018 12:38:59 +0200 Subject: [PATCH 12/27] androiddeployqt: Add auxiliary mode In this mode, library and other dependencies are copied into the build directory, and the XML templates in the build directory are updated accordingly, but the project is not built or installed. Needed by qbs. No existing code has been touched. Change-Id: Ib8015f7c2315b39dfb21750fecc8618bce03cb8c Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/tools/androiddeployqt/main.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) 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); From cf0ea18ac41c71418e84840d4933b126f0bf6b0a Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 29 Nov 2016 14:34:03 +0100 Subject: [PATCH 13/27] QWidgetWindow: Ensure Qt::WA_Mapped is set on obscured parent widgets Frameless obscured windows do not receive WM_PAINT/expose events on Windows. Qt::WA_Mapped needs to be set on them to ensure updating works. Task-number: QTBUG-39220 Task-number: QTBUG-52039 Task-number: QTBUG-58575 Task-number: QTBUG-63927 Change-Id: Ic6c11f2be96378b6a6b61296f1f3e13cd49b50a6 Reviewed-by: Andy Shaw --- src/widgets/kernel/qwidgetwindow.cpp | 3 ++ .../qwidget_window/tst_qwidget_window.cpp | 30 +++++++++++++++++++ 2 files changed, 33 insertions(+) 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/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 #include #include +#include +#include #include @@ -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(); From 07eda676e45f6c3c7237581c3f4a9e39695697ab Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 21 Aug 2018 10:41:17 +0200 Subject: [PATCH 14/27] Fix big-endian build Declare rbSwap, so we don't end up in a fallback definition not used by little-endian. Task-number: QTBUG-69951 Change-Id: I8512bba76da7d59a27593d37c70283d881c3e8fc Reviewed-by: Shawn Rutledge --- src/gui/painting/qdrawhelper.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index b1424b5b0a..4b68c22e95 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -640,6 +640,19 @@ void QT_FASTCALL rbSwap(uchar *d, const uchar *s, int c { return rbSwap_rgb32(d, s, count); } +#else +template<> +void QT_FASTCALL rbSwap(uchar *d, const uchar *s, int count) +{ + const uint *src = reinterpret_cast(s); + uint *dest = reinterpret_cast(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) From 76c328b2b39617310993ce76e65665943b8c111c Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 21 Aug 2018 15:52:52 +0200 Subject: [PATCH 15/27] Fix spacing in << operator for QEvent Turns QNativeGestureEvent(ZoomNativeGesturelocalPos=686.855,312.836, value=0.0259857) into QNativeGestureEvent(ZoomNativeGesture, localPos=686.855,312.836, value=0.0259857) Change-Id: Id30860a3c7a1b6da583369126a31934ddb32d4b9 Reviewed-by: Friedemann Kleint --- src/gui/kernel/qevent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index d7727d97b8..adc83302cf 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -4119,7 +4119,7 @@ QDebug operator<<(QDebug dbg, const QEvent *e) const QNativeGestureEvent *ne = static_cast(e); dbg << "QNativeGestureEvent("; QtDebugUtils::formatQEnum(dbg, ne->gestureType()); - dbg << "localPos="; + dbg << ", localPos="; QtDebugUtils::formatQPoint(dbg, ne->localPos()); dbg << ", value=" << ne->value() << ')'; } From dc82a0f4f3a380edfe910a78f3bdd32210975b85 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 21 Jun 2018 13:18:30 +0200 Subject: [PATCH 16/27] Smooth image scaling for 64bit images Adds support for smooth scaling 64bit images. Task-number: QTBUG-45858 Change-Id: If46030fb8e7d684159f852a3b8266a74e5e6700c Reviewed-by: Eirik Aavitsland --- src/gui/image/qimage.cpp | 14 +- src/gui/painting/qdrawhelper.cpp | 37 ---- src/gui/painting/qdrawhelper_p.h | 71 +++++++ src/gui/painting/qimagescale.cpp | 235 +++++++++++++++++++-- src/gui/painting/qrgba64_p.h | 13 -- tests/auto/gui/image/qimage/tst_qimage.cpp | 34 ++- 6 files changed, 325 insertions(+), 79 deletions(-) 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(reinterpret_cast(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(reinterpret_cast(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/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 4b68c22e95..98baffc740 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -2277,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 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(t)); + if (disty) { + uint64x1x2_t vb = vld2_u64(reinterpret_cast(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(&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 . 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/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("format"); + QTest::addColumn("format"); QTest::addColumn("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); - QImage img(size, size, (QImage::Format)format); + QRgb expected = opaque ? qRgb(63, 127, 255) : qRgba(31, 63, 127, 127); + + 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("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()); } } } From 5a1861399b1b8af97cdc1b4991b04a4bee69d5c8 Mon Sep 17 00:00:00 2001 From: David Faure Date: Sat, 28 Jul 2018 14:21:50 +0200 Subject: [PATCH 17/27] QFileDialog: make QFileDialog::selectFile resolve remote dirs correctly The code was assuming local files, and broke with remote dirs. Testcase: `kwrite sftp://localhost/tmp/file.txt` and then Ctrl+O, the initial directory was $PWD instead of the remote dir. Change-Id: Ie24d4c1b2b3278dce44274af0066105bd1bf9b34 Reviewed-by: Friedemann Kleint Reviewed-by: Christian Ehrlicher Reviewed-by: Luca Beldi Reviewed-by: Edward Welbourne --- src/widgets/dialogs/qfiledialog.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) 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() << url); From ee51a2c4dc8ed5522cc2477c397de08ee9872829 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Wed, 22 Aug 2018 11:37:25 +0200 Subject: [PATCH 18/27] tests: blacklist tst_QDialog::showFullScreen() on macOS 10.13 in CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-70109 Change-Id: I70b998c1853462f8ea2037cff59e9598923743e5 Reviewed-by: Tony Sarajärvi --- tests/auto/widgets/dialogs/qdialog/BLACKLIST | 2 ++ 1 file changed, 2 insertions(+) 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 From 991b251e391c0cbfaab7bd26dc5c344965a903d8 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 22 Aug 2018 10:11:13 +0200 Subject: [PATCH 19/27] Fix big-endian build of qopengltextureuploader Badly placed endif and lacking a break statement. Change-Id: Id6a3fb13b40e8ae8029e74f7668bafb6e0b9dd06 Reviewed-by: Shawn Rutledge --- src/gui/opengl/qopengltextureuploader.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gui/opengl/qopengltextureuploader.cpp b/src/gui/opengl/qopengltextureuploader.cpp index fc449d8090..1147c81471 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: From c9c770d775842a6c8ab60f951de25dd32b0bdb1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tony=20Saraj=C3=A4rvi?= Date: Wed, 22 Aug 2018 14:29:47 +0300 Subject: [PATCH 20/27] Extend blacklisting of tst_QWidget::maskedUpdate to cover all openSUSEs Fails on previous 42.3 and also 15.0. Just covering "opensuse" saves us from new commits every time we upgrade our openSUSE. We have a bug open of it after all. Task-number: QTBUG-51399 Change-Id: I5c0869daea41b1886faba3d0caaa0804a3705d54 Reviewed-by: Liang Qi --- tests/auto/widgets/kernel/qwidget/BLACKLIST | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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] From 38cb72b6fd34142785d0f791218d39ccafcfe84f Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Wed, 15 Aug 2018 20:35:28 +0200 Subject: [PATCH 21/27] Windows QPA: Force windows to the main screen in certain AMD GPU setups A multi-screen setup with an AMD adapter set as the 'main display' leads to using the AMD drivers for OpenGL. This then causes a crash when calling SetPixelFormat and similar for windows located on another adapter's screen. This workaround detects the conditions leading to the crash and moves the window to the main display. Task-number: QTBUG-50371 Change-Id: I4007c490bdcdc13d6e8bce82983b150aa4930338 Reviewed-by: Friedemann Kleint --- .../windows/qwindowsopengltester.cpp | 62 +++++++++++--- .../platforms/windows/qwindowsopengltester.h | 1 + .../platforms/windows/qwindowswindow.cpp | 84 ++++++++++++++++++- 3 files changed, 136 insertions(+), 11 deletions(-) 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 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() From 5ded4e35db321944157d431b885ba35f29ead68f Mon Sep 17 00:00:00 2001 From: Tamas Zakor Date: Wed, 22 Aug 2018 13:48:05 +0200 Subject: [PATCH 22/27] cups: Add a QT_CONFIG(dialogbuttonbox) guard This fixes build with -no-feature-action configuration. The corresponding dialog is added by: 6c5c1a562c cups: Show a dialog when asked for password Change-Id: Ic88bdd62c756749959e66252427b5edc2c3ce7cc Reviewed-by: Albert Astals Cid Reviewed-by: Oswald Buddenhagen --- src/plugins/printsupport/cups/qcupsprintersupport.cpp | 6 ++++++ 1 file changed, 6 insertions(+) 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 +#if QT_CONFIG(dialogbuttonbox) #include #include #include #include #include #include +#endif // QT_CONFIG(dialogbuttonbox) #include #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(QCoreApplication::instance())) cupsSetPasswordCB2(getPasswordCB, nullptr /* user_data */ ); +#endif // QT_CONFIG(dialogbuttonbox) } QCupsPrinterSupport::~QCupsPrinterSupport() From e498a1d09d79cbb26437a4823b67ae56c5542514 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 14 Sep 2017 16:13:53 +0200 Subject: [PATCH 23/27] Tablet example: add a menu item to clear the canvas It's annoying to have to kill the app and start over when it gets too cluttered. Change-Id: Ic72e372e5742de4e7c6bb818a3150283498a517b Reviewed-by: Friedemann Kleint --- examples/widgets/widgets/tablet/mainwindow.cpp | 16 +++++++++++++--- examples/widgets/widgets/tablet/mainwindow.h | 3 ++- examples/widgets/widgets/tablet/tabletcanvas.cpp | 6 ++++++ examples/widgets/widgets/tablet/tabletcanvas.h | 1 + 4 files changed, 22 insertions(+), 4 deletions(-) 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) From a88645c6f45188d93c6ca0a591aaeae2b3c4d5c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 23 Aug 2018 13:56:58 +0200 Subject: [PATCH 24/27] macOS: Share deployment target and device arch config between makespecs Change-Id: Ie06705590b4962d8b09b97e30625ef11af321763 Reviewed-by: Oswald Buddenhagen --- mkspecs/common/macx.conf | 3 +++ mkspecs/macx-clang/qmake.conf | 4 ---- mkspecs/macx-g++/qmake.conf | 4 ---- mkspecs/macx-icc/qmake.conf | 4 ---- 4 files changed, 3 insertions(+), 12 deletions(-) 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) From 4f6fa5b2ae839e01468f0e96b0f68d948811c31e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Wed, 22 Aug 2018 13:03:34 +0200 Subject: [PATCH 25/27] configure: add sources matching names from vcpkg It's possible to use vcpkg using the -I and -L arguments, but some of their libraries have different names than what we look for during configure, so add in those variations. Change-Id: Iee37197228cc0f15442ecd7ec4fc761f4d526e1d Reviewed-by: Oswald Buddenhagen --- configure.json | 1 + src/gui/configure.json | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) 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/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": [ From 2ab804c4520a8fa8e5aa69cebcf2f2f4441057c1 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 23 Aug 2018 12:45:56 +0200 Subject: [PATCH 26/27] clangcl: Fix QtGui link error (missing fetchPixelsBPP24_ssse3) Do not try using SSSE3 if the compiler do not support it. (see 648ee7aa020d04b160ec56187f49f761ffab93cc). Task-number: QTBUG-50804 Change-Id: I489b0bbacfde0c647c9d5b71ca3de992d7dc8878 Reviewed-by: Friedemann Kleint --- src/gui/painting/qdrawhelper.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 98baffc740..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(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 *, QDitherInfo *) { constexpr QPixelLayout::BPP BPP = bitsPerPixel(); -#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 *, QDitherInfo *) { constexpr QPixelLayout::BPP BPP = bitsPerPixel(); -#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. From ed557c037847e343caa010562952b398f806adcd Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 23 Aug 2018 12:50:36 +0200 Subject: [PATCH 27/27] Handle uploading of faked sub-images One trick that is possible to do with QImage is to make it be sub image of its imagedata by manipulating the data start and bytes-per-line, we can not upload that directly and need to detect the case and create a clean copy to upload. Task-number: QTBUG-70105 Change-Id: I7ce184a0892fb4071b6dcc1a1fd3881a4e0703cd Reviewed-by: Simon Hausmann Reviewed-by: Liang Qi --- src/gui/opengl/qopengltextureuploader.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/gui/opengl/qopengltextureuploader.cpp b/src/gui/opengl/qopengltextureuploader.cpp index 1147c81471..2428baed93 100644 --- a/src/gui/opengl/qopengltextureuploader.cpp +++ b/src/gui/opengl/qopengltextureuploader.cpp @@ -313,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;