From 2e0b0be2ce30394269559590b42c81de27301ee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 14 Aug 2019 12:39:27 +0200 Subject: Get rid of QWidgetBackingStoreTracker It was added for Symbian almost 10 years ago (d7057e7c1f1a), for a somewhat dubious use-case. The Symbian code is since long gone (ae30d7141), so the remaining pieces are just adding complexity to the already intricate workings of the QtWidgets backingstore/painting logic. Task-number: QTBUG-8697 Change-Id: I82af610a8ac26719c588ac63f06b4501f59b400d Reviewed-by: Paul Olav Tvete --- src/widgets/kernel/qwidget.cpp | 105 ++-------------------- src/widgets/kernel/qwidget_p.h | 48 +--------- src/widgets/kernel/qwidgetbackingstore.cpp | 10 +-- src/widgets/kernel/qwidgetwindow.cpp | 2 +- tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp | 9 +- 5 files changed, 18 insertions(+), 156 deletions(-) diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index ba9b2a0487..066dfaa183 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -146,91 +146,6 @@ static inline bool qRectIntersects(const QRect &r1, const QRect &r2) extern bool qt_sendSpontaneousEvent(QObject*, QEvent*); // qapplication.cpp extern QDesktopWidget *qt_desktopWidget; // qapplication.cpp -/*! - \internal - \class QWidgetBackingStoreTracker - \brief Class which allows tracking of which widgets are using a given backing store - - QWidgetBackingStoreTracker is a thin wrapper around a QWidgetBackingStore pointer, - which maintains a list of the QWidgets which are currently using the backing - store. This list is modified via the registerWidget and unregisterWidget functions. - */ - -QWidgetBackingStoreTracker::QWidgetBackingStoreTracker() - : m_ptr(0) -{ - -} - -QWidgetBackingStoreTracker::~QWidgetBackingStoreTracker() -{ - delete m_ptr; -} - -/*! - \internal - Destroy the contained QWidgetBackingStore, if not null, and clear the list of - widgets using the backing store, then create a new QWidgetBackingStore, providing - the QWidget. - */ -void QWidgetBackingStoreTracker::create(QWidget *widget) -{ - destroy(); - m_ptr = new QWidgetBackingStore(widget); -} - -/*! - \internal - Destroy the contained QWidgetBackingStore, if not null, and clear the list of - widgets using the backing store. - */ -void QWidgetBackingStoreTracker::destroy() -{ - delete m_ptr; - m_ptr = 0; - m_widgets.clear(); -} - -/*! - \internal - Add the widget to the list of widgets currently using the backing store. - If the widget was already in the list, this function is a no-op. - */ -void QWidgetBackingStoreTracker::registerWidget(QWidget *w) -{ - Q_ASSERT(m_ptr); - Q_ASSERT(w->internalWinId()); - Q_ASSERT(qt_widget_private(w)->maybeBackingStore() == m_ptr); - m_widgets.insert(w); -} - -/*! - \internal - Remove the widget from the list of widgets currently using the backing store. - If the widget was in the list, and removing it causes the list to be empty, - the backing store is deleted. - If the widget was not in the list, this function is a no-op. - */ -void QWidgetBackingStoreTracker::unregisterWidget(QWidget *w) -{ - if (m_widgets.remove(w) && m_widgets.isEmpty()) { - delete m_ptr; - m_ptr = 0; - } -} - -/*! - \internal - Recursively remove widget and all of its descendents. - */ -void QWidgetBackingStoreTracker::unregisterWidgetSubtree(QWidget *widget) -{ - unregisterWidget(widget); - foreach (QObject *child, widget->children()) - if (QWidget *childWidget = qobject_cast(child)) - unregisterWidgetSubtree(childWidget); -} - QWidgetPrivate::QWidgetPrivate(int version) : QObjectPrivate(version) , extra(0) @@ -1364,10 +1279,8 @@ void QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow) d->create(); // a real toplevel window needs a backing store - if (isWindow() && windowType() != Qt::Desktop) { - d->topData()->backingStoreTracker.destroy(); - d->topData()->backingStoreTracker.create(this); - } + if (isWindow() && windowType() != Qt::Desktop) + d->topData()->widgetBackingStore.reset(new QWidgetBackingStore(this)); d->setModal_sys(); @@ -1891,7 +1804,7 @@ void QWidgetPrivate::deleteTLSysExtra() //the qplatformbackingstore may hold a reference to the window, so the backingstore //needs to be deleted first. - extra->topextra->backingStoreTracker.destroy(); + extra->topextra->widgetBackingStore.reset(nullptr); deleteBackingStore(this); #ifndef QT_NO_OPENGL extra->topextra->widgetTextures.clear(); @@ -10755,16 +10668,8 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) if (newParent && isAncestorOf(focusWidget())) focusWidget()->clearFocus(); - QTLWExtra *oldTopExtra = window()->d_func()->maybeTopData(); - QWidgetBackingStoreTracker *oldBsTracker = oldTopExtra ? &oldTopExtra->backingStoreTracker : 0; - d->setParent_sys(parent, f); - QTLWExtra *topExtra = window()->d_func()->maybeTopData(); - QWidgetBackingStoreTracker *bsTracker = topExtra ? &topExtra->backingStoreTracker : 0; - if (oldBsTracker && oldBsTracker != bsTracker) - oldBsTracker->unregisterWidgetSubtree(this); - if (desktopWidget) parent = 0; @@ -11134,7 +11039,7 @@ void QWidgetPrivate::repaint(T r) QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData(); if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) - tlwExtra->backingStoreTracker->markDirty(r, q, QWidgetBackingStore::UpdateNow); + tlwExtra->widgetBackingStore->markDirty(r, q, QWidgetBackingStore::UpdateNow); } /*! @@ -11209,7 +11114,7 @@ void QWidgetPrivate::update(T r) QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData(); if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) - tlwExtra->backingStoreTracker->markDirty(clipped, q); + tlwExtra->widgetBackingStore->markDirty(clipped, q); } /*! diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index 970f5c0378..b4a9d283db 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -116,56 +116,12 @@ protected: QRegion m_region; }; - - -class Q_AUTOTEST_EXPORT QWidgetBackingStoreTracker -{ - -public: - QWidgetBackingStoreTracker(); - ~QWidgetBackingStoreTracker(); - - void create(QWidget *tlw); - void destroy(); - - void registerWidget(QWidget *w); - void unregisterWidget(QWidget *w); - void unregisterWidgetSubtree(QWidget *w); - - inline QWidgetBackingStore* data() - { - return m_ptr; - } - - inline QWidgetBackingStore* operator->() - { - return m_ptr; - } - - inline QWidgetBackingStore& operator*() - { - return *m_ptr; - } - - inline operator bool() const - { - return (nullptr != m_ptr); - } - -private: - Q_DISABLE_COPY_MOVE(QWidgetBackingStoreTracker) - -private: - QWidgetBackingStore* m_ptr; - QSet m_widgets; -}; - struct QTLWExtra { // *************************** Cross-platform variables ***************************** // Regular pointers (keep them together to avoid gaps on 64 bits architectures). std::unique_ptr icon; // widget icon - QWidgetBackingStoreTracker backingStoreTracker; + std::unique_ptr widgetBackingStore; QBackingStore *backingStore; QPainter *sharedPainter; QWidgetWindow *window; @@ -1028,7 +984,7 @@ inline QWidgetBackingStore *QWidgetPrivate::maybeBackingStore() const { Q_Q(const QWidget); QTLWExtra *x = q->window()->d_func()->maybeTopData(); - return x ? x->backingStoreTracker.data() : nullptr; + return x ? x->widgetBackingStore.get() : nullptr; } QT_END_NAMESPACE diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp index 009ffb17a1..1b963010d1 100644 --- a/src/widgets/kernel/qwidgetbackingstore.cpp +++ b/src/widgets/kernel/qwidgetbackingstore.cpp @@ -300,7 +300,7 @@ void QWidgetBackingStore::unflushPaint(QWidget *widget, const QRegion &rgn) if (!tlwExtra) return; - qt_flush(widget, rgn, tlwExtra->backingStoreTracker->store, tlw, 0, tlw->d_func()->maybeBackingStore()); + qt_flush(widget, rgn, tlwExtra->widgetBackingStore->store, tlw, 0, tlw->d_func()->maybeBackingStore()); } #endif // QT_NO_PAINT_DEBUG @@ -800,7 +800,7 @@ void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy) invalidateBackingStore((newRect & clipR).translated(-data.crect.topLeft())); } else { - QWidgetBackingStore *wbs = x->backingStoreTracker.data(); + QWidgetBackingStore *wbs = x->widgetBackingStore.get(); QRegion childExpose(newRect & clipR); QRegion overlappedExpose; @@ -864,7 +864,7 @@ void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy) if (x->inTopLevelResize) return; - QWidgetBackingStore *wbs = x->backingStoreTracker.data(); + QWidgetBackingStore *wbs = x->widgetBackingStore.get(); if (!wbs) return; @@ -1528,10 +1528,10 @@ void QWidgetPrivate::invalidateBackingStore(const T &r) if (masked.isEmpty()) return; - tlwExtra->backingStoreTracker->markDirty(masked, q, + tlwExtra->widgetBackingStore->markDirty(masked, q, QWidgetBackingStore::UpdateLater, QWidgetBackingStore::BufferInvalid); } else { - tlwExtra->backingStoreTracker->markDirty(clipped, q, + tlwExtra->widgetBackingStore->markDirty(clipped, q, QWidgetBackingStore::UpdateLater, QWidgetBackingStore::BufferInvalid); } } diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 5537ff497a..a01a377956 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -770,7 +770,7 @@ void QWidgetWindow::repaintWindow() QTLWExtra *tlwExtra = m_widget->window()->d_func()->maybeTopData(); if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) - tlwExtra->backingStoreTracker->markDirty(m_widget->rect(), m_widget, + tlwExtra->widgetBackingStore->markDirty(m_widget->rect(), m_widget, QWidgetBackingStore::UpdateNow, QWidgetBackingStore::BufferInvalid); } diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index bfc2631842..715bbbec0f 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -9564,7 +9565,7 @@ void tst_QWidget::destroyBackingStore() QTRY_VERIFY(w.numPaintEvents > 0); w.reset(); w.update(); - qt_widget_private(&w)->topData()->backingStoreTracker.create(&w); + qt_widget_private(&w)->topData()->widgetBackingStore.reset(new QWidgetBackingStore(&w)); w.update(); QApplication::processEvents(); @@ -9584,7 +9585,7 @@ QWidgetBackingStore* backingStore(QWidget &widget) QWidgetBackingStore *backingStore = nullptr; #ifdef QT_BUILD_INTERNAL if (QTLWExtra *topExtra = qt_widget_private(&widget)->maybeTopData()) - backingStore = topExtra->backingStoreTracker.data(); + backingStore = topExtra->widgetBackingStore.get(); #endif return backingStore; } @@ -9784,12 +9785,12 @@ class scrollWidgetWBS : public QWidget public: void deleteBackingStore() { - static_cast(d_ptr.data())->topData()->backingStoreTracker.destroy(); + static_cast(d_ptr.data())->topData()->widgetBackingStore.reset(nullptr); } void enableBackingStore() { if (!static_cast(d_ptr.data())->maybeBackingStore()) { - static_cast(d_ptr.data())->topData()->backingStoreTracker.create(this); + static_cast(d_ptr.data())->topData()->widgetBackingStore.reset(new QWidgetBackingStore(this)); static_cast(d_ptr.data())->invalidateBackingStore(this->rect()); repaint(); } -- cgit v1.2.3 From 662fec6f0db32fb58b91357aa11c9d3be94f0c55 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Fri, 9 Aug 2019 11:04:27 +0200 Subject: Update for failures only on dev branch. Use general platform names This patch was generated with tooling from patchset 31 of https://codereview.qt-project.org/c/qt/qtqa/+/267034 in interactive mode. General platform names were chosen if greater than 60% of the currently active platforms of a given type in COIN recently failed. Change-Id: Ia4bde7f0ec422bbb727dc9d7151295159094f146 Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../corelib/animation/qpauseanimation/BLACKLIST | 8 +- tests/auto/corelib/io/qfilesystemwatcher/BLACKLIST | 4 +- tests/auto/corelib/io/qprocess/BLACKLIST | 1 - tests/auto/corelib/kernel/qelapsedtimer/BLACKLIST | 3 +- .../auto/corelib/kernel/qsocketnotifier/BLACKLIST | 3 +- tests/auto/corelib/kernel/qtimer/BLACKLIST | 9 - .../corelib/serialization/qtextstream/BLACKLIST | 3 +- tests/auto/corelib/thread/qsemaphore/BLACKLIST | 3 +- tests/auto/corelib/thread/qthread/BLACKLIST | 4 +- tests/auto/corelib/thread/qthreadpool/BLACKLIST | 7 +- tests/auto/corelib/tools/qtimeline/BLACKLIST | 4 +- tests/auto/gui/kernel/qguitimer/BLACKLIST | 8 - tests/auto/gui/kernel/qwindow/BLACKLIST | 15 +- .../network/access/qabstractnetworkcache/BLACKLIST | 2 - tests/auto/network/access/qftp/BLACKLIST | 9 +- tests/auto/network/access/qnetworkreply/BLACKLIST | 191 ++++----------------- tests/auto/network/access/spdy/BLACKLIST | 3 - tests/auto/network/kernel/qdnslookup/BLACKLIST | 12 +- .../network/socket/qsocks5socketengine/BLACKLIST | 3 +- tests/auto/network/socket/qtcpserver/BLACKLIST | 14 +- tests/auto/network/socket/qtcpsocket/BLACKLIST | 3 - tests/auto/network/socket/qudpsocket/BLACKLIST | 6 - tests/auto/network/ssl/qsslkey/BLACKLIST | 17 +- tests/auto/network/ssl/qsslsocket/BLACKLIST | 4 - tests/auto/other/networkselftest/BLACKLIST | 3 +- tests/auto/other/qfocusevent/BLACKLIST | 3 - .../BLACKLIST | 3 +- .../widgets/dialogs/qfilesystemmodel/BLACKLIST | 11 +- tests/auto/widgets/dialogs/qmessagebox/BLACKLIST | 6 +- .../widgets/graphicsview/qgraphicsscene/BLACKLIST | 2 - .../widgets/graphicsview/qgraphicsview/BLACKLIST | 12 +- tests/auto/widgets/itemviews/qheaderview/BLACKLIST | 1 - tests/auto/widgets/kernel/qapplication/BLACKLIST | 3 +- tests/auto/widgets/kernel/qwidget/BLACKLIST | 10 +- 34 files changed, 74 insertions(+), 316 deletions(-) delete mode 100644 tests/auto/corelib/kernel/qtimer/BLACKLIST delete mode 100644 tests/auto/gui/kernel/qguitimer/BLACKLIST delete mode 100644 tests/auto/network/access/qabstractnetworkcache/BLACKLIST delete mode 100644 tests/auto/other/qfocusevent/BLACKLIST diff --git a/tests/auto/corelib/animation/qpauseanimation/BLACKLIST b/tests/auto/corelib/animation/qpauseanimation/BLACKLIST index 53372ce9ae..33cd53d788 100644 --- a/tests/auto/corelib/animation/qpauseanimation/BLACKLIST +++ b/tests/auto/corelib/animation/qpauseanimation/BLACKLIST @@ -1,9 +1,5 @@ [pauseAndPropertyAnimations] -osx-10.12 -osx-10.14 -osx-10.13 +osx [multipleSequentialGroups] -osx-10.12 -osx-10.14 -osx-10.13 +osx diff --git a/tests/auto/corelib/io/qfilesystemwatcher/BLACKLIST b/tests/auto/corelib/io/qfilesystemwatcher/BLACKLIST index 9b210b0d5f..457499591d 100644 --- a/tests/auto/corelib/io/qfilesystemwatcher/BLACKLIST +++ b/tests/auto/corelib/io/qfilesystemwatcher/BLACKLIST @@ -1,9 +1,7 @@ # QTBUG-33574 QTBUG-30943 [signalsEmittedAfterFileMoved] -windows-10 msvc-2017 -windows-10 msvc-2019 -windows-10 msvc-2015 windows-7sp1 +windows-10 [watchFileAndItsDirectory:native backend-testfile] osx windows diff --git a/tests/auto/corelib/io/qprocess/BLACKLIST b/tests/auto/corelib/io/qprocess/BLACKLIST index aa9fdab64d..682bcbc60c 100644 --- a/tests/auto/corelib/io/qprocess/BLACKLIST +++ b/tests/auto/corelib/io/qprocess/BLACKLIST @@ -2,6 +2,5 @@ redhatenterpriselinuxworkstation-6.6 # QTBUG-48455 [fileWriterProcess] -windows-10 msvc-2015 windows-10 msvc-2017 diff --git a/tests/auto/corelib/kernel/qelapsedtimer/BLACKLIST b/tests/auto/corelib/kernel/qelapsedtimer/BLACKLIST index 4c9fe53c14..569880e1db 100644 --- a/tests/auto/corelib/kernel/qelapsedtimer/BLACKLIST +++ b/tests/auto/corelib/kernel/qelapsedtimer/BLACKLIST @@ -1,4 +1,3 @@ [elapsed] -windows-10 msvc-2015 osx-10.13 -windows-10 msvc-2017 +windows-10 diff --git a/tests/auto/corelib/kernel/qsocketnotifier/BLACKLIST b/tests/auto/corelib/kernel/qsocketnotifier/BLACKLIST index f3b7fc97b1..f2e5e78592 100644 --- a/tests/auto/corelib/kernel/qsocketnotifier/BLACKLIST +++ b/tests/auto/corelib/kernel/qsocketnotifier/BLACKLIST @@ -1,4 +1,3 @@ [unexpectedDisconnection] -osx-10.12 -windows-10 msvc-2015 windows-7sp1 +windows-10 msvc-2015 diff --git a/tests/auto/corelib/kernel/qtimer/BLACKLIST b/tests/auto/corelib/kernel/qtimer/BLACKLIST deleted file mode 100644 index dc8b8987e5..0000000000 --- a/tests/auto/corelib/kernel/qtimer/BLACKLIST +++ /dev/null @@ -1,9 +0,0 @@ -[remainingTime] -osx-10.12 -osx-10.14 -osx-10.13 -windows-10 msvc-2017 -[basic_chrono] -osx-10.14 -osx-10.13 - diff --git a/tests/auto/corelib/serialization/qtextstream/BLACKLIST b/tests/auto/corelib/serialization/qtextstream/BLACKLIST index b8c1b742f4..674569e204 100644 --- a/tests/auto/corelib/serialization/qtextstream/BLACKLIST +++ b/tests/auto/corelib/serialization/qtextstream/BLACKLIST @@ -1,4 +1,3 @@ [stillOpenWhenAtEnd] -windows-10 msvc-2017 -winrt windows-7sp1 +winrt diff --git a/tests/auto/corelib/thread/qsemaphore/BLACKLIST b/tests/auto/corelib/thread/qsemaphore/BLACKLIST index f61f4c1a3b..d7af5c420b 100644 --- a/tests/auto/corelib/thread/qsemaphore/BLACKLIST +++ b/tests/auto/corelib/thread/qsemaphore/BLACKLIST @@ -1,6 +1,5 @@ [tryAcquireWithTimeout] -osx-10.12 -osx-10.13 +osx [tryAcquireWithTimeout:0.2s] windows osx-10.12 diff --git a/tests/auto/corelib/thread/qthread/BLACKLIST b/tests/auto/corelib/thread/qthread/BLACKLIST index 87538a1048..c683154da1 100644 --- a/tests/auto/corelib/thread/qthread/BLACKLIST +++ b/tests/auto/corelib/thread/qthread/BLACKLIST @@ -1,7 +1,5 @@ [wait3_slowDestructor] -windows-10 msvc-2015 -windows-7sp1 -windows-10 msvc-2017 +windows-10 [sleep] windows-7sp1 diff --git a/tests/auto/corelib/thread/qthreadpool/BLACKLIST b/tests/auto/corelib/thread/qthreadpool/BLACKLIST index e4f2fcd822..b8c1f3bf3f 100644 --- a/tests/auto/corelib/thread/qthreadpool/BLACKLIST +++ b/tests/auto/corelib/thread/qthreadpool/BLACKLIST @@ -1,7 +1,4 @@ [expiryTimeoutRace] -rhel-7.6 opensuse-leap -osx-10.13 -ubuntu-18.04 -osx-10.12 -opensuse-42.3 +ubuntu +rhel diff --git a/tests/auto/corelib/tools/qtimeline/BLACKLIST b/tests/auto/corelib/tools/qtimeline/BLACKLIST index b60cab31fa..9794b0059f 100644 --- a/tests/auto/corelib/tools/qtimeline/BLACKLIST +++ b/tests/auto/corelib/tools/qtimeline/BLACKLIST @@ -1,8 +1,6 @@ [interpolation] -osx-10.12 windows-10 msvc-2015 -osx-10.13 -windows-7sp1 +osx [frameRate] osx-10.12 osx-10.13 diff --git a/tests/auto/gui/kernel/qguitimer/BLACKLIST b/tests/auto/gui/kernel/qguitimer/BLACKLIST deleted file mode 100644 index 6ab715b922..0000000000 --- a/tests/auto/gui/kernel/qguitimer/BLACKLIST +++ /dev/null @@ -1,8 +0,0 @@ -[basic_chrono] -osx-10.13 -[remainingTime] -osx-10.12 -windows-10 msvc-2015 -osx-10.14 -osx-10.13 - diff --git a/tests/auto/gui/kernel/qwindow/BLACKLIST b/tests/auto/gui/kernel/qwindow/BLACKLIST index 1bb3917948..27463adf99 100644 --- a/tests/auto/gui/kernel/qwindow/BLACKLIST +++ b/tests/auto/gui/kernel/qwindow/BLACKLIST @@ -1,7 +1,5 @@ [positioning] opensuse-leap -ubuntu-16.04 -opensuse-42.3 [positioning:default] linux osx-10.12 ci @@ -9,24 +7,17 @@ winrt [positioning:fake] osx-10.12 ci [modalWithChildWindow] -ubuntu-16.04 -opensuse-leap # QTBUG-66851 # QTBUG-69160 -opensuse-42.3 +opensuse-leap [setVisible] # QTBUG-69154 android [modalWindowEnterEventOnHide_QTBUG35109] -ubuntu-16.04 -osx-10.11 -osx-10.13 -osx-10.14 -osx-10.12 +osx [spuriousMouseMove] # QTBUG-69162 -windows-10 msvc-2015 -windows-10 msvc-2017 +windows-10 [testInputEvents] rhel-7.4 [exposeEventOnShrink_QTBUG54040] diff --git a/tests/auto/network/access/qabstractnetworkcache/BLACKLIST b/tests/auto/network/access/qabstractnetworkcache/BLACKLIST deleted file mode 100644 index 12f45f0e12..0000000000 --- a/tests/auto/network/access/qabstractnetworkcache/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[cacheControl] -windows-10 msvc-2015 diff --git a/tests/auto/network/access/qftp/BLACKLIST b/tests/auto/network/access/qftp/BLACKLIST index 463030a089..0a99f3eb00 100644 --- a/tests/auto/network/access/qftp/BLACKLIST +++ b/tests/auto/network/access/qftp/BLACKLIST @@ -7,15 +7,10 @@ redhatenterpriselinuxworkstation-6.6 redhatenterpriselinuxworkstation-6.6 [list] -ubuntu-16.04 opensuse-leap -osx-10.11 windows-7sp1 -ubuntu-18.04 -osx-10.14 -b2qt -osx-10.12 windows-10 msvc-2015 -opensuse-42.3 +ubuntu +osx [list:epsvNotSupported] * diff --git a/tests/auto/network/access/qnetworkreply/BLACKLIST b/tests/auto/network/access/qnetworkreply/BLACKLIST index f9bbdd96c3..2a0651f96f 100644 --- a/tests/auto/network/access/qnetworkreply/BLACKLIST +++ b/tests/auto/network/access/qnetworkreply/BLACKLIST @@ -1,106 +1,53 @@ # See qtbase/src/testlib/qtestblacklist.cpp for format [authenticationCacheAfterCancel] -windows-10 msvc-2017 -windows-10 msvc-2015 -osx-10.13 windows-7sp1 -[httpAbort] -ubuntu-16.04 -rhel-7.6 +windows-10 msvc-2015 [backgroundRequestInterruption] -ubuntu-16.04 opensuse-leap -ubuntu-18.04 -b2qt -osx-10.12 windows-10 msvc-2015 -opensuse-42.3 +b2qt +ubuntu +osx [backgroundRequestInterruption:ftp, bg, nobg] * -[getErrors] -osx-10.13 -# QTBUG-71953 [getErrors:ftp-host] linux # QTBUG-71953 [getFromHttp] -rhel-6.6 -ubuntu-16.04 -rhel-7.6 -opensuse-leap -osx-10.11 -osx-10.13 -windows-7sp1 -ubuntu-18.04 -osx-10.14 -rhel-7.4 -b2qt -windows-10 msvc-2017 -osx-10.12 -windows-10 msvc-2015 -opensuse-42.3 +* !android !winrt [getFromHttp:success-external] * [getFromHttpIntoBuffer] -osx-10.12 -osx-10.13 +osx [getFromHttpIntoBuffer2] -windows-10 msvc-2015 -windows-10 msvc-2017 +windows-10 [headFromHttp] -osx-10.13 windows-10 msvc-2017 -[ioGetFromHttpWithSocksProxy] -osx-10.12 [ioPostToHttpFromSocket] # QTBUG-66247 -osx-10.13 windows-7sp1 windows-10 msvc-2017 -osx-10.12 -windows-10 msvc-2015 +osx [ioHttpRedirect] -windows-10 msvc-2015 # QTBUG-66602 -windows-10 msvc-2017 +windows-10 [ioHttpRedirectMultipartPost] -ubuntu-16.04 -rhel-7.6 # QTBUG-66247 -opensuse-leap -osx-10.13 -ubuntu-18.04 -rhel-7.4 b2qt -osx-10.12 windows-10 msvc-2015 -opensuse-42.3 +ubuntu +rhel [ioHttpRedirectPolicy] -ubuntu-16.04 opensuse-leap -windows-7sp1 -ubuntu-18.04 b2qt -windows-10 msvc-2017 -windows-10 msvc-2015 -opensuse-42.3 -[ioHttpRedirectPostPut] -osx-10.12 -windows-10 msvc-2015 +ubuntu +windows-10 [putToFtp] -windows-10 msvc-2017 +windows-10 [putWithServerClosingConnectionImmediately] -osx-10.11 -osx-10.13 -windows-7sp1 -windows-10 msvc-2017 -osx-10.12 -windows-10 msvc-2015 -[qtbug28035browserDoesNotLoadQtProjectOrgCorrectly] -windows-10 msvc-2015 windows-7sp1 -[authenticationWithDifferentRealm] -osx-10.13 +windows-10 +osx [backgroundRequest] osx-10.12 [connectToIPv6Address] @@ -109,141 +56,73 @@ osx-10.12 osx-10.12 [downloadProgress] osx-10.12 -[emitErrorForAllReplies] -osx-10.12 [encrypted] osx-10.13 -[ftpAuthentication] -osx-10.13 [httpCanReadLine] osx-10.12 -osx-10.13 [httpRecursiveCreation] -osx-10.12 -osx-10.13 +osx [httpWithNoCredentialUsage] osx-10.12 [ignoreSslErrorsList] -osx-10.12 -osx-10.13 +osx [ignoreSslErrorsListWithSlot] -osx-10.12 -osx-10.13 +osx [ioGetFromBuiltinHttp] -osx-10.12 -osx-10.11 -osx-10.14 -osx-10.13 +osx [ioGetFromHttp] osx-10.12 -[ioGetFromHttpWithAuth] -osx-10.12 -osx-10.13 -[ioGetFromHttpWithAuthSynchronous] -osx-10.12 -[ioGetFromHttpWithProxyAuth] -osx-10.12 -[ioGetFromHttpWithReuseParallel] -osx-10.12 -osx-10.13 -[ioGetFromHttpWithReuseSequential] -osx-10.12 -osx-10.13 -[ioGetFromHttpsWithIgnoreSslErrors] -osx-10.12 -[ioGetFromHttpsWithSslErrors] -osx-10.12 -[ioGetFromHttpsWithSslHandshakeError] -osx-10.12 -[ioGetWithManyProxies] -osx-10.12 [ioPostToHttpFromFile] osx-10.13 -[ioPostToHttpFromMiddleOfFileFiveBytes] -osx-10.13 -[ioPostToHttpFromMiddleOfFileToEnd] -osx-10.13 -[ioPostToHttpFromMiddleOfQBufferFiveBytes] -osx-10.13 [ioPostToHttpFromSocketSynchronous] -osx-10.12 -osx-10.13 -[ioPostToHttpNoBufferFlag] -osx-10.13 +osx [ioPostToHttpUploadProgress] -osx-10.12 -osx-10.11 -osx-10.13 +osx [ioPutToHttpFromFile] osx-10.13 [lastModifiedHeaderForHttp] osx-10.12 -osx-10.13 [multipartSkipIndices] osx-10.12 -osx-10.13 [nestedEventLoops] -osx-10.12 -osx-10.13 -[pipelining] -osx-10.13 +osx [postToHttp] osx-10.12 -osx-10.13 [postToHttpMultipart] osx-10.12 -osx-10.13 [postToHttpSynchronous] osx-10.12 -osx-10.13 [postToHttps] -osx-10.12 -osx-10.13 +osx [postToHttpsMultipart] -osx-10.12 -osx-10.13 +osx [postToHttpsSynchronous] -osx-10.12 -osx-10.13 +osx [putGetDeleteGetFromHttp] osx-10.12 -[putToHttp] -osx-10.12 -osx-10.13 [putToHttpSynchronous] osx-10.12 -osx-10.13 [putToHttps] -osx-10.12 -osx-10.13 +osx [putToHttpsSynchronous] -osx-10.12 -osx-10.13 +osx [putWithRateLimiting] -osx-10.12 osx-10.13 [qtbug13431replyThrottling] osx-10.12 [receiveCookiesFromHttp] -osx-10.12 -osx-10.13 +osx [receiveCookiesFromHttpSynchronous] -osx-10.12 -osx-10.13 +osx [sendCookies] -osx-10.12 -osx-10.13 +osx [sendCookiesSynchronous] -osx-10.12 -osx-10.13 +osx [sendCustomRequestToHttp] osx-10.12 [sslConfiguration] -osx-10.12 -osx-10.13 +osx [synchronousRequest] -osx-10.12 -osx-10.13 +osx [backgroundRequestConnectInBackground] -osx-10.12 -osx-10.13 +osx diff --git a/tests/auto/network/access/spdy/BLACKLIST b/tests/auto/network/access/spdy/BLACKLIST index ce2f7f383f..5cf79327be 100644 --- a/tests/auto/network/access/spdy/BLACKLIST +++ b/tests/auto/network/access/spdy/BLACKLIST @@ -1,8 +1,5 @@ [download] opensuse-leap -ubuntu-18.04 -ubuntu-16.04 -b2qt [upload] opensuse-leap ubuntu-18.04 diff --git a/tests/auto/network/kernel/qdnslookup/BLACKLIST b/tests/auto/network/kernel/qdnslookup/BLACKLIST index 4461d8b5f7..f07a8ce9a3 100644 --- a/tests/auto/network/kernel/qdnslookup/BLACKLIST +++ b/tests/auto/network/kernel/qdnslookup/BLACKLIST @@ -1,12 +1,2 @@ [lookup] -rhel-7.6 -opensuse-leap -osx-10.13 -windows-7sp1 -ubuntu-18.04 -rhel-7.4 -b2qt -windows-10 msvc-2017 -osx-10.12 -windows-10 msvc-2015 -opensuse-42.3 +* diff --git a/tests/auto/network/socket/qsocks5socketengine/BLACKLIST b/tests/auto/network/socket/qsocks5socketengine/BLACKLIST index f769aafbdd..61fff6ee00 100644 --- a/tests/auto/network/socket/qsocks5socketengine/BLACKLIST +++ b/tests/auto/network/socket/qsocks5socketengine/BLACKLIST @@ -4,8 +4,7 @@ ubuntu-18.04 # QTBUG-74162 [passwordAuth2] -osx-10.12 -ubuntu-18.04 +ubuntu [downloadBigFile] windows-10 msvc-2015 windows-7sp1 diff --git a/tests/auto/network/socket/qtcpserver/BLACKLIST b/tests/auto/network/socket/qtcpserver/BLACKLIST index ad0edf0af1..e268468bdb 100644 --- a/tests/auto/network/socket/qtcpserver/BLACKLIST +++ b/tests/auto/network/socket/qtcpserver/BLACKLIST @@ -1,24 +1,16 @@ -[listenWhileListening] -windows-10 msvc-2015 [listenWhileListening:WithSocks5Proxy] linux windows [ipv6Server] -windows-10 msvc-2015 windows-7sp1 windows-10 msvc-2017 [ipv6Server:WithoutProxy] windows osx -[addressReusable] -windows-10 msvc-2015 [eagainBlockingAccept] -windows-10 msvc-2015 -windows-7sp1 -windows-10 msvc-2017 -[proxyFactory] windows-7sp1 +windows-10 [serverAddress] -windows-10 msvc-2017 -windows-10 msvc-2015 windows-7sp1 +windows-10 + diff --git a/tests/auto/network/socket/qtcpsocket/BLACKLIST b/tests/auto/network/socket/qtcpsocket/BLACKLIST index 8c2f8d2638..07532710b3 100644 --- a/tests/auto/network/socket/qtcpsocket/BLACKLIST +++ b/tests/auto/network/socket/qtcpsocket/BLACKLIST @@ -5,9 +5,6 @@ windows-7sp1 windows [bind:[::]:randomport] windows -[timeoutConnect] -windows-10 msvc-2015 -# QTBUG-66247 [timeoutConnect:ip] windows # QTBUG-66247 diff --git a/tests/auto/network/socket/qudpsocket/BLACKLIST b/tests/auto/network/socket/qudpsocket/BLACKLIST index 9b5aa8a3fc..bc6068d695 100644 --- a/tests/auto/network/socket/qudpsocket/BLACKLIST +++ b/tests/auto/network/socket/qudpsocket/BLACKLIST @@ -2,15 +2,9 @@ windows-10 msvc-2017 windows-10 msvc-2015 windows-7sp1 -[multicastLeaveAfterClose] -osx-10.12 -osx-10.11 [readyReadForEmptyDatagram] opensuse-leap -ubuntu-16.04 [echo] opensuse-42.3 -[ipv6Loop] -osx-10.12 [readyReadForEmptyDatagram] linux diff --git a/tests/auto/network/ssl/qsslkey/BLACKLIST b/tests/auto/network/ssl/qsslkey/BLACKLIST index e9723001f5..19fb15cd1f 100644 --- a/tests/auto/network/ssl/qsslkey/BLACKLIST +++ b/tests/auto/network/ssl/qsslkey/BLACKLIST @@ -1,16 +1,9 @@ [constructor] -rhel-6.6 -rhel-7.4 -rhel-7.6 +rhel [length] -rhel-6.6 -rhel-7.4 -rhel-7.6 +rhel [toEncryptedPemOrDer] -rhel-6.6 -rhel-7.4 -rhel-7.6 +rhel [toPemOrDer] -rhel-6.6 -rhel-7.4 -rhel-7.6 +rhel + diff --git a/tests/auto/network/ssl/qsslsocket/BLACKLIST b/tests/auto/network/ssl/qsslsocket/BLACKLIST index 36143691c9..7b4a29f463 100644 --- a/tests/auto/network/ssl/qsslsocket/BLACKLIST +++ b/tests/auto/network/ssl/qsslsocket/BLACKLIST @@ -1,11 +1,7 @@ -[abortOnSslErrors] -windows-10 msvc-2015 [deprecatedProtocols] windows [spontaneousWrite] windows-7sp1 -[sslErrors] -windows-7sp1 [connectToHostEncrypted] osx-10.13 [setSslConfiguration] diff --git a/tests/auto/other/networkselftest/BLACKLIST b/tests/auto/other/networkselftest/BLACKLIST index 948081eb78..55ebad985d 100644 --- a/tests/auto/other/networkselftest/BLACKLIST +++ b/tests/auto/other/networkselftest/BLACKLIST @@ -1,6 +1,5 @@ # QTBUG-27571 [ftpProxyServer] -windows-10 msvc-2017 -windows-10 msvc-2015 windows-7sp1 +windows-10 diff --git a/tests/auto/other/qfocusevent/BLACKLIST b/tests/auto/other/qfocusevent/BLACKLIST deleted file mode 100644 index 5af8be91a0..0000000000 --- a/tests/auto/other/qfocusevent/BLACKLIST +++ /dev/null @@ -1,3 +0,0 @@ -[checkReason_ActiveWindow] -winrt - diff --git a/tests/auto/other/qnetworkaccessmanager_and_qprogressdialog/BLACKLIST b/tests/auto/other/qnetworkaccessmanager_and_qprogressdialog/BLACKLIST index 65a939cdcb..6173488c00 100644 --- a/tests/auto/other/qnetworkaccessmanager_and_qprogressdialog/BLACKLIST +++ b/tests/auto/other/qnetworkaccessmanager_and_qprogressdialog/BLACKLIST @@ -1,5 +1,4 @@ [downloadCheck] -windows-10 msvc-2015 -windows-10 msvc-2017 +windows-10 [downloadCheck:with-zeroCopy] windows diff --git a/tests/auto/widgets/dialogs/qfilesystemmodel/BLACKLIST b/tests/auto/widgets/dialogs/qfilesystemmodel/BLACKLIST index f2f0f8d26e..aae2cacc3b 100644 --- a/tests/auto/widgets/dialogs/qfilesystemmodel/BLACKLIST +++ b/tests/auto/widgets/dialogs/qfilesystemmodel/BLACKLIST @@ -7,13 +7,10 @@ b2qt [specialFiles] b2qt [dirsBeforeFiles] -ubuntu-16.04 -rhel-7.6 -windows-10 msvc-2017 -ubuntu-18.04 -b2qt winrt -windows-10 msvc-2015 - +b2qt +ubuntu +windows-10 +rhel [drives] winrt diff --git a/tests/auto/widgets/dialogs/qmessagebox/BLACKLIST b/tests/auto/widgets/dialogs/qmessagebox/BLACKLIST index e633e7c0a3..8d8a7c2105 100644 --- a/tests/auto/widgets/dialogs/qmessagebox/BLACKLIST +++ b/tests/auto/widgets/dialogs/qmessagebox/BLACKLIST @@ -1,6 +1,4 @@ [defaultButton] -ubuntu-16.04 -rhel-7.6 opensuse-leap -ubuntu-18.04 -rhel-7.4 +rhel-7.6 +ubuntu diff --git a/tests/auto/widgets/graphicsview/qgraphicsscene/BLACKLIST b/tests/auto/widgets/graphicsview/qgraphicsscene/BLACKLIST index a3c9e2e421..c3797c9d57 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsscene/BLACKLIST +++ b/tests/auto/widgets/graphicsview/qgraphicsscene/BLACKLIST @@ -1,7 +1,5 @@ [isActive] opensuse-42.3 ci -[removeFullyTransparentItem] -osx-10.12 [tabFocus_sceneWithNestedFocusWidgets] opensuse-42.3 diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/BLACKLIST b/tests/auto/widgets/graphicsview/qgraphicsview/BLACKLIST index 22fce8620b..9b76ea02ff 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsview/BLACKLIST +++ b/tests/auto/widgets/graphicsview/qgraphicsview/BLACKLIST @@ -1,24 +1,16 @@ [task255529_transformationAnchorMouseAndViewportMargins] opensuse-leap -rhel-7.4 -ubuntu-16.04 -opensuse-42.3 [cursor] opensuse-leap -ubuntu-16.04 -opensuse-42.3 [cursor2] ubuntu-16.04 [sendEvent] ubuntu-16.04 opensuse-42.3 [resizeAnchor] -ubuntu-16.04 -rhel-7.6 opensuse-leap -ubuntu-18.04 -rhel-7.4 -opensuse-42.3 +rhel-7.6 +ubuntu [update2] opensuse-42.3 [itemsInRect_cosmeticAdjust] diff --git a/tests/auto/widgets/itemviews/qheaderview/BLACKLIST b/tests/auto/widgets/itemviews/qheaderview/BLACKLIST index 297a6fe7b7..4eceaae0d3 100644 --- a/tests/auto/widgets/itemviews/qheaderview/BLACKLIST +++ b/tests/auto/widgets/itemviews/qheaderview/BLACKLIST @@ -1,3 +1,2 @@ [stretchAndRestoreLastSection] opensuse-leap -opensuse-42.3 diff --git a/tests/auto/widgets/kernel/qapplication/BLACKLIST b/tests/auto/widgets/kernel/qapplication/BLACKLIST index ac65a97c40..c68c7d6b14 100644 --- a/tests/auto/widgets/kernel/qapplication/BLACKLIST +++ b/tests/auto/widgets/kernel/qapplication/BLACKLIST @@ -1,4 +1,3 @@ [touchEventPropagation] -opensuse-leap # QTBUG-66745 -opensuse-42.3 +opensuse-leap diff --git a/tests/auto/widgets/kernel/qwidget/BLACKLIST b/tests/auto/widgets/kernel/qwidget/BLACKLIST index 02e97e4b4e..26f9ce1b85 100644 --- a/tests/auto/widgets/kernel/qwidget/BLACKLIST +++ b/tests/auto/widgets/kernel/qwidget/BLACKLIST @@ -14,12 +14,9 @@ rhel-7.4 ubuntu-16.04 rhel-7.6 [focusProxyAndInputMethods] -ubuntu-16.04 rhel-7.6 opensuse-leap -ubuntu-18.04 -rhel-7.4 -opensuse-42.3 +ubuntu [raise] opensuse-leap # QTBUG-68175 @@ -45,12 +42,9 @@ opensuse-leap [moveInResizeEvent] ubuntu-16.04 [multipleToplevelFocusCheck] -ubuntu-16.04 rhel-7.6 opensuse-leap -ubuntu-18.04 -rhel-7.4 -opensuse-42.3 +ubuntu [windowState] # QTBUG-75270 winrt -- cgit v1.2.3 From f5c118b6b8397c70e875f98cac745c3325c1167f Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Mon, 15 Jul 2019 12:49:30 +0200 Subject: Fix escaping of additional app parameters in adb shell command Change-Id: I80e5b98efbc9654c684b3d78ba0d6688c21bd0f3 Reviewed-by: BogDan Vatra --- src/tools/androidtestrunner/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/androidtestrunner/main.cpp b/src/tools/androidtestrunner/main.cpp index e6d6f72354..a035e068bc 100644 --- a/src/tools/androidtestrunner/main.cpp +++ b/src/tools/androidtestrunner/main.cpp @@ -362,7 +362,7 @@ static bool parseTestArgs() g_options.testArgs += QStringLiteral(" -o output.%1,%1").arg(format); g_options.testArgs += unhandledArgs; - g_options.testArgs = QStringLiteral("shell am start -e applicationArguments \"'%1'\" -n %2/%3").arg(shellQuote(g_options.testArgs.trimmed()), + g_options.testArgs = QStringLiteral("shell am start -e applicationArguments \\\"%1\\\" -n %2/%3").arg(shellQuote(g_options.testArgs.trimmed()), g_options.package, g_options.activity); return true; -- cgit v1.2.3 From 427995a518310c0e3bf956d558a41f18fadeab68 Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Sun, 18 Aug 2019 10:53:01 +0200 Subject: Itemmodel tests: remove foreach usage Replace foreach with range-based for loop, replace some int values with the correct Qt flag enum as drive-by. Change-Id: I41c52f6ae6c537fa9ad4f9e169485533936952d1 Reviewed-by: Marc Mutz Reviewed-by: Volker Hilsheimer --- .../qabstractitemmodel/tst_qabstractitemmodel.cpp | 2 +- .../tst_qitemselectionmodel.cpp | 83 ++++++++++++---------- .../tst_qsortfilterproxymodel.cpp | 30 ++++---- 3 files changed, 60 insertions(+), 55 deletions(-) diff --git a/tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp b/tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp index 3a4493474b..f305edb2c5 100644 --- a/tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp +++ b/tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp @@ -1830,7 +1830,7 @@ void ListenerObject::slotAboutToBeReset() void ListenerObject::slotReset() { - foreach (const QModelIndex &idx, m_persistentIndexes) { + for (const auto &idx : qAsConst(m_persistentIndexes)) { QVERIFY(!idx.isValid()); } } diff --git a/tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp b/tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp index f78f5bc138..c74101928a 100644 --- a/tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp +++ b/tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp @@ -32,6 +32,9 @@ #include +Q_DECLARE_METATYPE(QItemSelectionModel::SelectionFlag) +Q_DECLARE_METATYPE(Qt::SortOrder) + class tst_QItemSelectionModel : public QObject { Q_OBJECT @@ -1463,7 +1466,7 @@ void tst_QItemSelectionModel::persistentselections() QFETCH(IntList, insertColumns); QFETCH(IntList, deleteRows); QFETCH(IntList, deleteColumns); - QFETCH(PairList, expectedList); + QFETCH(const PairList, expectedList); // make sure the model is sane (5x5) QCOMPARE(model->rowCount(QModelIndex()), 5); @@ -1504,7 +1507,7 @@ void tst_QItemSelectionModel::persistentselections() // check that the selected items are the correct number and indexes QModelIndexList selectedList = selection->selectedIndexes(); QCOMPARE(selectedList.count(), expectedList.count()); - foreach(IntPair pair, expectedList) { + for (const auto &pair : expectedList) { QModelIndex index = model->index(pair.first, pair.second, QModelIndex()); QVERIFY(selectedList.contains(index)); } @@ -1679,7 +1682,7 @@ void tst_QItemSelectionModel::modelLayoutChanged_data() { QTest::addColumn("items"); QTest::addColumn("initialSelectedRanges"); - QTest::addColumn("sortOrder"); + QTest::addColumn("sortOrder"); QTest::addColumn("sortColumn"); QTest::addColumn("expectedSelectedRanges"); @@ -1689,7 +1692,7 @@ void tst_QItemSelectionModel::modelLayoutChanged_data() << (IntList() << 3 << 2 << 1 << 0)) << (IntPairPairList() << IntPairPair(IntPair(0, 0), IntPair(3, 1))) - << int(Qt::DescendingOrder) + << Qt::DescendingOrder << 0 << (IntPairPairList() << IntPairPair(IntPair(0, 0), IntPair(3, 1))); @@ -1699,7 +1702,7 @@ void tst_QItemSelectionModel::modelLayoutChanged_data() << (IntList() << 3 << 2 << 1 << 0)) << (IntPairPairList() << IntPairPair(IntPair(0, 0), IntPair(1, 1))) - << int(Qt::DescendingOrder) + << Qt::DescendingOrder << 0 << (IntPairPairList() << IntPairPair(IntPair(2, 0), IntPair(3, 1))); @@ -1709,7 +1712,7 @@ void tst_QItemSelectionModel::modelLayoutChanged_data() << (IntList() << 3 << 2 << 1 << 0)) << (IntPairPairList() << IntPairPair(IntPair(1, 0), IntPair(2, 1))) - << int(Qt::DescendingOrder) + << Qt::DescendingOrder << 0 << (IntPairPairList() << IntPairPair(IntPair(1, 0), IntPair(2, 1))); @@ -1720,7 +1723,7 @@ void tst_QItemSelectionModel::modelLayoutChanged_data() << (IntPairPairList() << IntPairPair(IntPair(1, 0), IntPair(1, 1)) << IntPairPair(IntPair(3, 0), IntPair(3, 1))) - << int(Qt::AscendingOrder) + << Qt::AscendingOrder << 0 << (IntPairPairList() << IntPairPair(IntPair(0, 0), IntPair(0, 1)) @@ -1730,8 +1733,8 @@ void tst_QItemSelectionModel::modelLayoutChanged_data() void tst_QItemSelectionModel::modelLayoutChanged() { QFETCH(IntListList, items); - QFETCH(IntPairPairList, initialSelectedRanges); - QFETCH(int, sortOrder); + QFETCH(const IntPairPairList, initialSelectedRanges); + QFETCH(Qt::SortOrder, sortOrder); QFETCH(int, sortColumn); QFETCH(IntPairPairList, expectedSelectedRanges); @@ -1746,9 +1749,9 @@ void tst_QItemSelectionModel::modelLayoutChanged() // select initial ranges QItemSelectionModel selectionModel(&model); - foreach (IntPairPair range, initialSelectedRanges) { - IntPair tl = range.first; - IntPair br = range.second; + for (const auto &range : initialSelectedRanges) { + const auto &tl = range.first; + const auto &br = range.second; QItemSelection selection( model.index(tl.first, tl.second), model.index(br.first, br.second)); @@ -1756,7 +1759,7 @@ void tst_QItemSelectionModel::modelLayoutChanged() } // sort the model - model.sort(sortColumn, Qt::SortOrder(sortOrder)); + model.sort(sortColumn, sortOrder); // verify that selection is as expected QItemSelection selection = selectionModel.selection(); @@ -2126,43 +2129,43 @@ void tst_QItemSelectionModel::merge_data() { QTest::addColumn("init"); QTest::addColumn("other"); - QTest::addColumn("command"); + QTest::addColumn("command"); QTest::addColumn("result"); QTest::newRow("Simple select") << QItemSelection() << QItemSelection(model->index(2, 1) , model->index(3, 4)) - << int(QItemSelectionModel::Select) + << QItemSelectionModel::Select << QItemSelection(model->index(2, 1) , model->index(3, 4)); QTest::newRow("Simple deselect") << QItemSelection(model->index(2, 1) , model->index(3, 4)) << QItemSelection(model->index(2, 1) , model->index(3, 4)) - << int(QItemSelectionModel::Deselect) + << QItemSelectionModel::Deselect << QItemSelection(); QTest::newRow("Simple Toggle deselect") << QItemSelection(model->index(2, 1) , model->index(3, 4)) << QItemSelection(model->index(2, 1) , model->index(3, 4)) - << int(QItemSelectionModel::Toggle) + << QItemSelectionModel::Toggle << QItemSelection(); QTest::newRow("Simple Toggle select") << QItemSelection() << QItemSelection(model->index(2, 1) , model->index(3, 4)) - << int(QItemSelectionModel::Toggle) + << QItemSelectionModel::Toggle << QItemSelection(model->index(2, 1) , model->index(3, 4)); QTest::newRow("Add select") << QItemSelection(model->index(2, 1) , model->index(3, 3)) << QItemSelection(model->index(2, 2) , model->index(3, 4)) - << int(QItemSelectionModel::Select) + << QItemSelectionModel::Select << QItemSelection(model->index(2, 1) , model->index(3, 4)); QTest::newRow("Deselect") << QItemSelection(model->index(2, 1) , model->index(3, 4)) << QItemSelection(model->index(2, 2) , model->index(3, 4)) - << int(QItemSelectionModel::Deselect) + << QItemSelectionModel::Deselect << QItemSelection(model->index(2, 1) , model->index(3, 1)); QItemSelection r1(model->index(2, 1) , model->index(3, 1)); @@ -2170,7 +2173,7 @@ void tst_QItemSelectionModel::merge_data() QTest::newRow("Toggle") << QItemSelection(model->index(2, 1) , model->index(3, 3)) << QItemSelection(model->index(2, 2) , model->index(3, 4)) - << int(QItemSelectionModel::Toggle) + << QItemSelectionModel::Toggle << r1; } @@ -2178,15 +2181,18 @@ void tst_QItemSelectionModel::merge() { QFETCH(QItemSelection, init); QFETCH(QItemSelection, other); - QFETCH(int, command); + QFETCH(QItemSelectionModel::SelectionFlag, command); QFETCH(QItemSelection, result); - init.merge(other, QItemSelectionModel::SelectionFlags(command)); + init.merge(other, command); - foreach(const QModelIndex &idx, init.indexes()) - QVERIFY(result.contains(idx)); - foreach(const QModelIndex &idx, result.indexes()) - QVERIFY(init.contains(idx)); + auto verify = [](const QModelIndexList &a, const QItemSelection &b) + { + for (const QModelIndex &idx : a) + QVERIFY(b.contains(idx)); + }; + verify(init.indexes(), result); + verify(result.indexes(), init); } void tst_QItemSelectionModel::isRowSelected() @@ -2267,13 +2273,12 @@ void tst_QItemSelectionModel::layoutChangedWithAllSelected1() proxy.setFilterRegularExpression(QRegularExpression("f")); QCOMPARE(proxy.rowCount(), 2); - QList indexList; - indexList << proxy.index(0,0) << proxy.index(1,0); - selection.select( QItemSelection(indexList.first(), indexList.last()), QItemSelectionModel::Select); + const QList indexList({proxy.index(0,0), proxy.index(1,0)}); + selection.select(QItemSelection(indexList.first(), indexList.last()), QItemSelectionModel::Select); //let's check the selection hasn't changed QCOMPARE(selection.selectedIndexes().count(), indexList.count()); - foreach(QPersistentModelIndex index, indexList) + for (const auto &index : indexList) QVERIFY(selection.isSelected(index)); proxy.setFilterRegularExpression(QRegularExpression()); @@ -2281,7 +2286,7 @@ void tst_QItemSelectionModel::layoutChangedWithAllSelected1() //let's check the selection hasn't changed QCOMPARE(selection.selectedIndexes().count(), indexList.count()); - foreach(QPersistentModelIndex index, indexList) + for (const auto &index : indexList) QVERIFY(selection.isSelected(index)); } @@ -2321,9 +2326,8 @@ void tst_QItemSelectionModel::layoutChangedWithAllSelected2() selection.select( QItemSelection(proxy.index(0,0), proxy.index(proxy.rowCount() - 1, proxy.columnCount() - 1)), QItemSelectionModel::Select); - QList indexList; - foreach(const QModelIndex &id, selection.selectedIndexes()) - indexList << id; + const auto selIndexes = selection.selectedIndexes(); + const QList indexList(selIndexes.begin(), selIndexes.end()); proxy.filtering = false; proxy.invalidate(); @@ -2331,7 +2335,7 @@ void tst_QItemSelectionModel::layoutChangedWithAllSelected2() //let's check the selection hasn't changed QCOMPARE(selection.selectedIndexes().count(), indexList.count()); - foreach(QPersistentModelIndex index, indexList) + for (const auto &index : indexList) QVERIFY(selection.isSelected(index)); } @@ -2375,7 +2379,8 @@ public: public slots: void selectionChanged(const QItemSelection & /* selected */, const QItemSelection &deselected) { - foreach(const QModelIndex &index, deselected.indexes()) { + const auto deselIndexes = deselected.indexes(); + for (const auto &index : deselIndexes) { QVERIFY(!m_itemSelectionModel->selection().contains(index)); } QCOMPARE(m_itemSelectionModel->selection().size(), 2); @@ -2633,9 +2638,9 @@ private slots: void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) { - foreach(const QItemSelectionRange &range, selected) + for (const auto &range : selected) QVERIFY(range.isValid()); - foreach(const QItemSelectionRange &range, deselected) + for (const auto &range : deselected) QVERIFY(range.isValid()); } diff --git a/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.cpp b/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.cpp index 0f7588a71a..624187349b 100644 --- a/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.cpp +++ b/tests/auto/corelib/itemmodels/qsortfilterproxymodel_common/tst_qsortfilterproxymodel.cpp @@ -829,7 +829,7 @@ void tst_QSortFilterProxyModel::removeRows_data() void tst_QSortFilterProxyModel::removeRows() { - QFETCH(QStringList, initial); + QFETCH(const QStringList, initial); QFETCH(int, sortOrder); QFETCH(QString, filter); QFETCH(int, position); @@ -843,7 +843,7 @@ void tst_QSortFilterProxyModel::removeRows() proxy.setSourceModel(&model); // prepare model - foreach (QString s, initial) + for (const auto &s : initial) model.appendRow(new QStandardItem(s)); if (sortOrder != -1) @@ -3035,15 +3035,15 @@ void tst_QSortFilterProxyModel::removeRowsRecursive() QList sourceIndexes; QList proxyIndexes; - foreach (QStandardItem *item, items) { + for (const auto item : qAsConst(items)) { QModelIndex idx = item->index(); sourceIndexes << idx; proxyIndexes << proxy.mapFromSource(idx); } - foreach (const QPersistentModelIndex &pidx, sourceIndexes) + for (const auto &pidx : qAsConst(sourceIndexes)) QVERIFY(pidx.isValid()); - foreach (const QPersistentModelIndex &pidx, proxyIndexes) + for (const auto &pidx : qAsConst(proxyIndexes)) QVERIFY(pidx.isValid()); QList itemRow = pItem1->takeRow(0); @@ -3051,9 +3051,9 @@ void tst_QSortFilterProxyModel::removeRowsRecursive() QCOMPARE(itemRow.count(), 1); QCOMPARE(itemRow.first(), pItem11); - foreach (const QPersistentModelIndex &pidx, sourceIndexes) + for (const auto &pidx : qAsConst(sourceIndexes)) QVERIFY(!pidx.isValid()); - foreach (const QPersistentModelIndex &pidx, proxyIndexes) + for (const auto &pidx : qAsConst(proxyIndexes)) QVERIFY(!pidx.isValid()); delete pItem11; @@ -3280,10 +3280,8 @@ void tst_QSortFilterProxyModel::testMultipleProxiesWithSelection() static bool isValid(const QItemSelection &selection) { - foreach (const QItemSelectionRange &range, selection) - if (!range.isValid()) - return false; - return true; + return std::all_of(selection.begin(), selection.end(), + [](const QItemSelectionRange &range) { return range.isValid(); }); } void tst_QSortFilterProxyModel::mapSelectionFromSource() @@ -3737,14 +3735,16 @@ void tst_QSortFilterProxyModel::testParentLayoutChanged() QVERIFY(beforeParents.first() == proxy.mapFromSource(model.indexFromItem(model.invisibleRootItem()->child(1)))); - QList proxy2BeforeList = proxy2ParentsAboutToBeChangedSpy.first().first().value >(); - QList proxy2AfterList = proxy2ParentsChangedSpy.first().first().value >(); + const QList proxy2BeforeList = + proxy2ParentsAboutToBeChangedSpy.first().first().value >(); + const QList proxy2AfterList = + proxy2ParentsChangedSpy.first().first().value >(); QCOMPARE(proxy2BeforeList.size(), beforeParents.size()); QCOMPARE(proxy2AfterList.size(), afterParents.size()); - foreach (const QPersistentModelIndex &idx, proxy2BeforeList) + for (const QPersistentModelIndex &idx : proxy2BeforeList) QVERIFY(beforeParents.contains(proxy2.mapToSource(idx))); - foreach (const QPersistentModelIndex &idx, proxy2AfterList) + for (const QPersistentModelIndex &idx : proxy2AfterList) QVERIFY(afterParents.contains(proxy2.mapToSource(idx))); } -- cgit v1.2.3 From 8240c24866550c4c083a7c1020d0b1b1bb7c8329 Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Sat, 1 Jun 2019 12:30:12 +0900 Subject: Fix build without feature.codecs Change-Id: I7113928c686319f132e6306f6925da009e8f41b1 Reviewed-by: Ulf Hermann --- src/corelib/codecs/qicucodec.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/corelib/codecs/qicucodec.cpp b/src/corelib/codecs/qicucodec.cpp index 101c3a3278..b9f1a814fa 100644 --- a/src/corelib/codecs/qicucodec.cpp +++ b/src/corelib/codecs/qicucodec.cpp @@ -42,8 +42,10 @@ #include "qtextcodec_p.h" #include "qutfcodec_p.h" #include "qlatincodec_p.h" +#if QT_CONFIG(codecs) #include "qtsciicodec_p.h" #include "qisciicodec_p.h" +#endif #include "qsimplecodec_p.h" #include "private/qcoreglobaldata_p.h" #include "qdebug.h" -- cgit v1.2.3 From d8a9bec35fb0c60a0e5990c1a12ffe6f39fdbf2d Mon Sep 17 00:00:00 2001 From: Nils Jeisecke Date: Thu, 17 Dec 2015 16:38:15 +0100 Subject: QTextDocument: add css-styling of table cell borders to HTML import/export Supported style attributes: style: supports "border-collapse: collapse" and "border-color". border: width of the outer border bordercolor: basic color for all borders style: not supported
/ style: supports the "border", "border-[top|left|bottom|right]]" shorthand styles and the "border-width", "border-color" and "border-style" (and the top/left/bottom/right variants) attributes will render a simple 1px table grid. Notes: The QTextDocument table model is much simpler than the HTML table model. It basically only has
and and
support. So the HTML parser is forced to map markup and styling to the QTextDocument model which is not without loss. In other words: While QTextDocument -> HTML -> QTextDocument should preserve the QTextDocument structure, HTML -> QTextDocument -> HTML does not preserve the HTML DOM at all. So for now the HTML importer and writer only support border styles on the and nodes. In future updates, the HTML parser might be enhanced to map
CSS styles to the cells. Change-Id: If9e7312fa6cbf270cf8f7b3c72ba1fa094107517 Reviewed-by: Shawn Rutledge --- src/gui/text/qcssparser.cpp | 9 ++ src/gui/text/qcssparser_p.h | 2 + src/gui/text/qtextdocument.cpp | 80 +++++++----- src/gui/text/qtextdocumentfragment.cpp | 26 ++++ src/gui/text/qtexthtmlparser.cpp | 34 ++++++ src/gui/text/qtexthtmlparser_p.h | 8 ++ .../gui/text/qtextdocument/tst_qtextdocument.cpp | 29 +++++ .../tst_qtextdocumentfragment.cpp | 134 +++++++++++++++++++++ tests/auto/gui/text/qtexttable/tst_qtexttable.cpp | 108 +++++++++++++++++ 9 files changed, 401 insertions(+), 29 deletions(-) diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp index 45f1ca596e..0b2dedf5dc 100644 --- a/src/gui/text/qcssparser.cpp +++ b/src/gui/text/qcssparser.cpp @@ -92,6 +92,7 @@ static const QCssKnownValue properties[NumProperties - 1] = { { "border-bottom-right-radius", BorderBottomRightRadius }, { "border-bottom-style", BorderBottomStyle }, { "border-bottom-width", BorderBottomWidth }, + { "border-collapse", BorderCollapse }, { "border-color", BorderColor }, { "border-image", BorderImage }, { "border-left", BorderLeft }, @@ -1732,6 +1733,14 @@ void Declaration::borderImageValue(QString *image, int *cuts, *h = *v; } +bool Declaration::borderCollapseValue() const +{ + if (d->values.count() != 1) + return false; + else + return d->values.at(0).toString() == QLatin1String("collapse"); +} + QIcon Declaration::iconValue() const { if (d->parsed.isValid()) diff --git a/src/gui/text/qcssparser_p.h b/src/gui/text/qcssparser_p.h index ddc46803ae..ab85e76cf3 100644 --- a/src/gui/text/qcssparser_p.h +++ b/src/gui/text/qcssparser_p.h @@ -122,6 +122,7 @@ enum Property { BorderRight, BorderTop, BorderBottom, + BorderCollapse, Padding, PaddingLeft, PaddingRight, @@ -478,6 +479,7 @@ struct Q_GUI_EXPORT Declaration QIcon iconValue() const; void borderImageValue(QString *image, int *cuts, TileMode *h, TileMode *v) const; + bool borderCollapseValue() const; }; QT_CSS_DECLARE_TYPEINFO(Declaration, Q_MOVABLE_TYPE) diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index dc34a96918..c80617f929 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -2593,51 +2593,43 @@ void QTextHtmlExporter::emitFloatStyle(QTextFrameFormat::Position pos, StyleMode html += QLatin1Char('\"'); } -void QTextHtmlExporter::emitBorderStyle(QTextFrameFormat::BorderStyle style) +static QLatin1String richtextBorderStyleToHtmlBorderStyle(QTextFrameFormat::BorderStyle style) { - Q_ASSERT(style <= QTextFrameFormat::BorderStyle_Outset); - - html += QLatin1String(" border-style:"); - switch (style) { case QTextFrameFormat::BorderStyle_None: - html += QLatin1String("none"); - break; + return QLatin1String("none"); case QTextFrameFormat::BorderStyle_Dotted: - html += QLatin1String("dotted"); - break; + return QLatin1String("dotted"); case QTextFrameFormat::BorderStyle_Dashed: - html += QLatin1String("dashed"); - break; + return QLatin1String("dashed"); case QTextFrameFormat::BorderStyle_Solid: - html += QLatin1String("solid"); - break; + return QLatin1String("solid"); case QTextFrameFormat::BorderStyle_Double: - html += QLatin1String("double"); - break; + return QLatin1String("double"); case QTextFrameFormat::BorderStyle_DotDash: - html += QLatin1String("dot-dash"); - break; + return QLatin1String("dot-dash"); case QTextFrameFormat::BorderStyle_DotDotDash: - html += QLatin1String("dot-dot-dash"); - break; + return QLatin1String("dot-dot-dash"); case QTextFrameFormat::BorderStyle_Groove: - html += QLatin1String("groove"); - break; + return QLatin1String("groove"); case QTextFrameFormat::BorderStyle_Ridge: - html += QLatin1String("ridge"); - break; + return QLatin1String("ridge"); case QTextFrameFormat::BorderStyle_Inset: - html += QLatin1String("inset"); - break; + return QLatin1String("inset"); case QTextFrameFormat::BorderStyle_Outset: - html += QLatin1String("outset"); - break; + return QLatin1String("outset"); default: - Q_ASSERT(false); - break; + Q_UNREACHABLE(); }; + return QLatin1String(""); +} + +void QTextHtmlExporter::emitBorderStyle(QTextFrameFormat::BorderStyle style) +{ + Q_ASSERT(style <= QTextFrameFormat::BorderStyle_Outset); + html += QLatin1String(" border-style:"); + html += richtextBorderStyleToHtmlBorderStyle(style); html += QLatin1Char(';'); } @@ -3204,6 +3196,33 @@ void QTextHtmlExporter::emitTable(const QTextTable *table) if (cellFormat.hasProperty(QTextFormat::TableCellBottomPadding)) styleString += QLatin1String(" padding-bottom:") + QString::number(cellFormat.bottomPadding()) + QLatin1Char(';'); + if (cellFormat.hasProperty(QTextFormat::TableCellTopBorder)) + styleString += QLatin1String(" border-top:") + QString::number(cellFormat.topBorder()) + QLatin1String("px;"); + if (cellFormat.hasProperty(QTextFormat::TableCellRightBorder)) + styleString += QLatin1String(" border-right:") + QString::number(cellFormat.rightBorder()) + QLatin1String("px;"); + if (cellFormat.hasProperty(QTextFormat::TableCellBottomBorder)) + styleString += QLatin1String(" border-bottom:") + QString::number(cellFormat.bottomBorder()) + QLatin1String("px;"); + if (cellFormat.hasProperty(QTextFormat::TableCellLeftBorder)) + styleString += QLatin1String(" border-left:") + QString::number(cellFormat.leftBorder()) + QLatin1String("px;"); + + if (cellFormat.hasProperty(QTextFormat::TableCellTopBorderBrush)) + styleString += QLatin1String(" border-top-color:") + cellFormat.topBorderBrush().color().name() + QLatin1Char(';'); + if (cellFormat.hasProperty(QTextFormat::TableCellRightBorderBrush)) + styleString += QLatin1String(" border-right-color:") + cellFormat.rightBorderBrush().color().name() + QLatin1Char(';'); + if (cellFormat.hasProperty(QTextFormat::TableCellBottomBorderBrush)) + styleString += QLatin1String(" border-bottom-color:") + cellFormat.bottomBorderBrush().color().name() + QLatin1Char(';'); + if (cellFormat.hasProperty(QTextFormat::TableCellLeftBorderBrush)) + styleString += QLatin1String(" border-left-color:") + cellFormat.leftBorderBrush().color().name() + QLatin1Char(';'); + + if (cellFormat.hasProperty(QTextFormat::TableCellTopBorderStyle)) + styleString += QLatin1String(" border-top-style:") + richtextBorderStyleToHtmlBorderStyle(cellFormat.topBorderStyle()) + QLatin1Char(';'); + if (cellFormat.hasProperty(QTextFormat::TableCellRightBorderStyle)) + styleString += QLatin1String(" border-right-style:") + richtextBorderStyleToHtmlBorderStyle(cellFormat.rightBorderStyle()) + QLatin1Char(';'); + if (cellFormat.hasProperty(QTextFormat::TableCellBottomBorderStyle)) + styleString += QLatin1String(" border-bottom-style:") + richtextBorderStyleToHtmlBorderStyle(cellFormat.bottomBorderStyle()) + QLatin1Char(';'); + if (cellFormat.hasProperty(QTextFormat::TableCellLeftBorderStyle)) + styleString += QLatin1String(" border-left-style:") + richtextBorderStyleToHtmlBorderStyle(cellFormat.leftBorderStyle()) + QLatin1Char(';'); + if (!styleString.isEmpty()) html += QLatin1String(" style=\"") + styleString + QLatin1Char('\"'); @@ -3310,6 +3329,9 @@ void QTextHtmlExporter::emitFrameStyle(const QTextFrameFormat &format, FrameType QString::number(format.leftMargin()), QString::number(format.rightMargin())); + if (format.property(QTextFormat::TableBorderCollapse).toBool()) + html += QLatin1String(" border-collapse:collapse;"); + if (html.length() == originalHtmlLength) // nothing emitted? html.chop(styleAttribute.size()); else diff --git a/src/gui/text/qtextdocumentfragment.cpp b/src/gui/text/qtextdocumentfragment.cpp index 8ad1300e6c..778493d4bc 100644 --- a/src/gui/text/qtextdocumentfragment.cpp +++ b/src/gui/text/qtextdocumentfragment.cpp @@ -986,6 +986,7 @@ QTextHtmlImporter::Table QTextHtmlImporter::scanTable(int tableNodeIdx) tableFmt.setColumns(table.columns); tableFmt.setColumnWidthConstraints(columnWidths); tableFmt.setHeaderRowCount(tableHeaderRowCount); + tableFmt.setBorderCollapse(node.borderCollapse); fmt = tableFmt; } @@ -1061,6 +1062,31 @@ QTextHtmlImporter::ProcessNodeResult QTextHtmlImporter::processBlockNode() fmt.setLeftPadding(leftPadding(currentNodeIdx)); if (rightPadding(currentNodeIdx) >= 0) fmt.setRightPadding(rightPadding(currentNodeIdx)); + if (tableCellBorder(currentNodeIdx, QCss::TopEdge) > 0) + fmt.setTopBorder(tableCellBorder(currentNodeIdx, QCss::TopEdge)); + if (tableCellBorder(currentNodeIdx, QCss::RightEdge) > 0) + fmt.setRightBorder(tableCellBorder(currentNodeIdx, QCss::RightEdge)); + if (tableCellBorder(currentNodeIdx, QCss::BottomEdge) > 0) + fmt.setBottomBorder(tableCellBorder(currentNodeIdx, QCss::BottomEdge)); + if (tableCellBorder(currentNodeIdx, QCss::LeftEdge) > 0) + fmt.setLeftBorder(tableCellBorder(currentNodeIdx, QCss::LeftEdge)); + if (tableCellBorderStyle(currentNodeIdx, QCss::TopEdge) != QTextFrameFormat::BorderStyle_None) + fmt.setTopBorderStyle(tableCellBorderStyle(currentNodeIdx, QCss::TopEdge)); + if (tableCellBorderStyle(currentNodeIdx, QCss::RightEdge) != QTextFrameFormat::BorderStyle_None) + fmt.setRightBorderStyle(tableCellBorderStyle(currentNodeIdx, QCss::RightEdge)); + if (tableCellBorderStyle(currentNodeIdx, QCss::BottomEdge) != QTextFrameFormat::BorderStyle_None) + fmt.setBottomBorderStyle(tableCellBorderStyle(currentNodeIdx, QCss::BottomEdge)); + if (tableCellBorderStyle(currentNodeIdx, QCss::LeftEdge) != QTextFrameFormat::BorderStyle_None) + fmt.setLeftBorderStyle(tableCellBorderStyle(currentNodeIdx, QCss::LeftEdge)); + if (tableCellBorderBrush(currentNodeIdx, QCss::TopEdge) != Qt::NoBrush) + fmt.setTopBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::TopEdge)); + if (tableCellBorderBrush(currentNodeIdx, QCss::RightEdge) != Qt::NoBrush) + fmt.setRightBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::RightEdge)); + if (tableCellBorderBrush(currentNodeIdx, QCss::BottomEdge) != Qt::NoBrush) + fmt.setBottomBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::BottomEdge)); + if (tableCellBorderBrush(currentNodeIdx, QCss::LeftEdge) != Qt::NoBrush) + fmt.setLeftBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::LeftEdge)); + cell.setFormat(fmt); cursor.setPosition(cell.firstPosition()); diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp index 43b32e7e2c..5d37982a8b 100644 --- a/src/gui/text/qtexthtmlparser.cpp +++ b/src/gui/text/qtexthtmlparser.cpp @@ -491,12 +491,19 @@ QTextHtmlParserNode::QTextHtmlParserNode() listStyle(QTextListFormat::ListStyleUndefined), imageWidth(-1), imageHeight(-1), tableBorder(0), tableCellRowSpan(1), tableCellColSpan(1), tableCellSpacing(2), tableCellPadding(0), borderBrush(Qt::darkGray), borderStyle(QTextFrameFormat::BorderStyle_Outset), + borderCollapse(false), userState(-1), cssListIndent(0), wsm(WhiteSpaceModeUndefined) { margin[QTextHtmlParser::MarginLeft] = 0; margin[QTextHtmlParser::MarginRight] = 0; margin[QTextHtmlParser::MarginTop] = 0; margin[QTextHtmlParser::MarginBottom] = 0; + + for (int i = 0; i < 4; ++i) { + tableCellBorderStyle[i] = QTextFrameFormat::BorderStyle_None; + tableCellBorder[i] = 0; + tableCellBorderBrush[i] = Qt::NoBrush; + } } void QTextHtmlParser::dumpHtml() @@ -1169,6 +1176,25 @@ void QTextHtmlParserNode::applyCssDeclarations(const QVector QCss::ValueExtractor extractor(declarations); extractor.extractBox(margin, padding); + if (id == Html_td || id == Html_th) { + QCss::BorderStyle cssStyles[4]; + int cssBorder[4]; + QSize cssRadii[4]; // unused + for (int i = 0; i < 4; ++i) { + cssStyles[i] = QCss::BorderStyle_None; + cssBorder[i] = 0; + } + // this will parse (and cache) "border-width" as a list so the + // QCss::BorderWidth parsing below which expects a single value + // will not work as expected - which in this case does not matter + // because tableBorder is not relevant for cells. + extractor.extractBorder(cssBorder, tableCellBorderBrush, cssStyles, cssRadii); + for (int i = 0; i < 4; ++i) { + tableCellBorderStyle[i] = static_cast(cssStyles[i] - 1); + tableCellBorder[i] = static_cast(cssBorder[i]); + } + } + for (int i = 0; i < declarations.count(); ++i) { const QCss::Declaration &decl = declarations.at(i); if (decl.d->values.isEmpty()) continue; @@ -1186,6 +1212,9 @@ void QTextHtmlParserNode::applyCssDeclarations(const QVector case QCss::BorderWidth: tableBorder = extractor.lengthValue(decl); break; + case QCss::BorderCollapse: + borderCollapse = decl.borderCollapseValue(); + break; case QCss::Color: charFormat.setForeground(decl.colorValue()); break; case QCss::Float: cssFloat = QTextFrameFormat::InFlow; @@ -1654,6 +1683,11 @@ void QTextHtmlParser::applyAttributes(const QStringList &attributes) if (!c.isValid()) qWarning("QTextHtmlParser::applyAttributes: Unknown color name '%s'",value.toLatin1().constData()); node->charFormat.setBackground(c); + } else if (key == QLatin1String("bordercolor")) { + QColor c; c.setNamedColor(value); + if (!c.isValid()) + qWarning("QTextHtmlParser::applyAttributes: Unknown color name '%s'",value.toLatin1().constData()); + node->borderBrush = c; } else if (key == QLatin1String("background")) { node->applyBackgroundImage(value, resourceProvider); } else if (key == QLatin1String("cellspacing")) { diff --git a/src/gui/text/qtexthtmlparser_p.h b/src/gui/text/qtexthtmlparser_p.h index ff5f5b4c35..31f558709f 100644 --- a/src/gui/text/qtexthtmlparser_p.h +++ b/src/gui/text/qtexthtmlparser_p.h @@ -195,8 +195,12 @@ struct QTextHtmlParserNode { int tableCellColSpan; qreal tableCellSpacing; qreal tableCellPadding; + qreal tableCellBorder[4]; + QBrush tableCellBorderBrush[4]; + QTextFrameFormat::BorderStyle tableCellBorderStyle[4]; QBrush borderBrush; QTextFrameFormat::BorderStyle borderStyle; + bool borderCollapse; int userState; int cssListIndent; @@ -290,6 +294,10 @@ public: inline int leftPadding(int i) const { return at(i).padding[MarginLeft]; } inline int rightPadding(int i) const { return at(i).padding[MarginRight]; } + inline qreal tableCellBorder(int i, int edge) const { return at(i).tableCellBorder[edge]; } + inline QTextFrameFormat::BorderStyle tableCellBorderStyle(int i, int edge) const { return at(i).tableCellBorderStyle[edge]; } + inline QBrush tableCellBorderBrush(int i, int edge) const { return at(i).tableCellBorderBrush[edge]; } + void dumpHtml(); void parse(const QString &text, const QTextDocument *resourceProvider); diff --git a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp index 58810f73c1..52e56feb5a 100644 --- a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp +++ b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp @@ -50,6 +50,7 @@ #include #include "common.h" +// #define DEBUG_WRITE_OUTPUT QT_FORWARD_DECLARE_CLASS(QTextDocument) @@ -196,6 +197,7 @@ private: void backgroundImage_checkExpectedHtml(const QTextDocument &doc); void buildRegExpData(); static QString cssFontSizeString(const QFont &font); + void writeActualAndExpected(const char* testTag, const QString &actual, const QString &expected); QTextDocument *doc; QTextCursor cursor; @@ -224,6 +226,27 @@ QString tst_QTextDocument::cssFontSizeString(const QFont &font) : QString::number(font.pixelSize()) + QStringLiteral("px"); } +void tst_QTextDocument::writeActualAndExpected(const char *testTag, const QString &actual, const QString &expected) +{ +#ifdef DEBUG_WRITE_OUTPUT + { + QFile out(QDir::temp().absoluteFilePath(QLatin1String(testTag) + QLatin1String("-actual.html"))); + out.open(QFile::WriteOnly); + out.write(actual.toUtf8()); + out.close(); + } { + QFile out(QDir::temp().absoluteFilePath(QLatin1String(testTag) + QLatin1String("-expected.html"))); + out.open(QFile::WriteOnly); + out.write(expected.toUtf8()); + out.close(); + } +#else + Q_UNUSED(testTag) + Q_UNUSED(actual) + Q_UNUSED(expected) +#endif +} + // Testing get/set functions void tst_QTextDocument::getSetCheck() { @@ -1765,6 +1788,8 @@ void tst_QTextDocument::toHtml() QString output = doc->toHtml(); + writeActualAndExpected(QTest::currentDataTag(), output, expectedOutput); + QCOMPARE(output, expectedOutput); QDomDocument document; @@ -1962,6 +1987,8 @@ void tst_QTextDocument::toHtmlRootFrameProperties() expectedOutput.replace("DEFAULTBLOCKSTYLE", "style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\""); expectedOutput.append(htmlTail); + writeActualAndExpected(QTest::currentTestFunction(), doc.toHtml(), expectedOutput); + QCOMPARE(doc.toHtml(), expectedOutput); } @@ -2734,6 +2761,8 @@ void tst_QTextDocument::backgroundImage_checkExpectedHtml(const QTextDocument &d .arg(defaultFont.weight() * 8) .arg((defaultFont.italic() ? "italic" : "normal")); + writeActualAndExpected(QTest::currentTestFunction(), doc.toHtml(), expectedHtml); + QCOMPARE(doc.toHtml(), expectedHtml); } diff --git a/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp b/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp index c5243d1535..b6917f1208 100644 --- a/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp +++ b/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp @@ -181,6 +181,11 @@ private slots: void html_tableCellBackground(); void css_bodyBackground(); void css_tableCellBackground(); + void css_tableCellBorder(); + void css_tableCellBorderShorthand(); + void css_tableCellAllBordersShorthand(); + void css_tableCellOverrideOneBorder(); + void css_tableBorderCollapse(); void css_fontWeight(); void css_float(); void css_textIndent(); @@ -1753,6 +1758,135 @@ void tst_QTextDocumentFragment::css_tableCellBackground() QCOMPARE(cell.format().background().style(), Qt::TexturePattern); } +void tst_QTextDocumentFragment::css_tableCellBorder() +{ + const char html[] = "
Foo
"; + doc->setHtml(html); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + + QTextTableCell cell = table->cellAt(0, 0); + QTextTableCellFormat cellFormat = cell.format().toTableCellFormat(); + QCOMPARE(cellFormat.leftBorder(), qreal(4)); + QCOMPARE(cellFormat.leftBorderBrush(), QBrush(QColor("red"))); + QCOMPARE(cellFormat.leftBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); + + QCOMPARE(cellFormat.rightBorder(), qreal(8)); + QCOMPARE(cellFormat.rightBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.rightBorderStyle(), QTextFrameFormat::BorderStyle_Groove); + + QCOMPARE(cellFormat.bottomBorder(), qreal(8)); + QCOMPARE(cellFormat.bottomBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.bottomBorderStyle(), QTextFrameFormat::BorderStyle_Groove); + + QCOMPARE(cellFormat.topBorder(), qreal(8)); + QCOMPARE(cellFormat.topBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.topBorderStyle(), QTextFrameFormat::BorderStyle_Groove); +} + +void tst_QTextDocumentFragment::css_tableCellBorderShorthand() +{ + const char html[] = "
Foo
"; + doc->setHtml(html); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + + QTextTableCell cell = table->cellAt(0, 0); + QTextTableCellFormat cellFormat = cell.format().toTableCellFormat(); + QCOMPARE(cellFormat.leftBorder(), qreal(1)); + QCOMPARE(cellFormat.leftBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.leftBorderStyle(), QTextFrameFormat::BorderStyle_Solid); + + QCOMPARE(cellFormat.rightBorder(), qreal(2)); + QCOMPARE(cellFormat.rightBorderBrush(), QBrush(QColor("red"))); + QCOMPARE(cellFormat.rightBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); + + QCOMPARE(cellFormat.bottomBorder(), qreal(3)); + QCOMPARE(cellFormat.bottomBorderBrush(), QBrush(QColor("yellow"))); + QCOMPARE(cellFormat.bottomBorderStyle(), QTextFrameFormat::BorderStyle_Dotted); + + QCOMPARE(cellFormat.topBorder(), qreal(4)); + QCOMPARE(cellFormat.topBorderBrush(), QBrush(QColor("blue"))); + QCOMPARE(cellFormat.topBorderStyle(), QTextFrameFormat::BorderStyle_DotDash); +} + +void tst_QTextDocumentFragment::css_tableCellAllBordersShorthand() +{ + const char html[] = "
Foo
"; + doc->setHtml(html); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + + QTextTableCell cell = table->cellAt(0, 0); + QTextTableCellFormat cellFormat = cell.format().toTableCellFormat(); + QCOMPARE(cellFormat.leftBorder(), qreal(2)); + QCOMPARE(cellFormat.leftBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.leftBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); + + QCOMPARE(cellFormat.rightBorder(), qreal(2)); + QCOMPARE(cellFormat.rightBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.rightBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); + + QCOMPARE(cellFormat.bottomBorder(), qreal(2)); + QCOMPARE(cellFormat.bottomBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.bottomBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); + + QCOMPARE(cellFormat.topBorder(), qreal(2)); + QCOMPARE(cellFormat.topBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.topBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); +} + +void tst_QTextDocumentFragment::css_tableCellOverrideOneBorder() +{ + const char html[] = "
Foo
"; + doc->setHtml(html); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + + QTextTableCell cell = table->cellAt(0, 0); + QTextTableCellFormat cellFormat = cell.format().toTableCellFormat(); + QCOMPARE(cellFormat.leftBorder(), qreal(4)); + QCOMPARE(cellFormat.leftBorderBrush(), QBrush(QColor("red"))); + QCOMPARE(cellFormat.leftBorderStyle(), QTextFrameFormat::BorderStyle_Solid); + + QCOMPARE(cellFormat.rightBorder(), qreal(2)); + QCOMPARE(cellFormat.rightBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.rightBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); + + QCOMPARE(cellFormat.bottomBorder(), qreal(2)); + QCOMPARE(cellFormat.bottomBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.bottomBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); + + QCOMPARE(cellFormat.topBorder(), qreal(2)); + QCOMPARE(cellFormat.topBorderBrush(), QBrush(QColor("green"))); + QCOMPARE(cellFormat.topBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); +} + +void tst_QTextDocumentFragment::css_tableBorderCollapse() +{ + const char html[] = "
Foo
"; + doc->setHtml(html); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + + QCOMPARE(table->format().borderCollapse(), true); +} + void tst_QTextDocumentFragment::css_cellPaddings() { const char html[] = "" diff --git a/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp b/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp index f21b969aa7..7b2ff4cc10 100644 --- a/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp +++ b/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp @@ -50,6 +50,8 @@ typedef QList IntList; QT_FORWARD_DECLARE_CLASS(QTextDocument) +Q_DECLARE_METATYPE(QTextFrameFormat::BorderStyle); + class tst_QTextTable : public QObject { Q_OBJECT @@ -95,6 +97,8 @@ private slots: #if !defined(QT_NO_PRINTER) && defined(QT_BUILD_INTERNAL) void QTBUG31330_renderBackground(); #endif + void checkBorderAttributes_data(); + void checkBorderAttributes(); private: QTextTable *create2x2Table(); @@ -1170,5 +1174,109 @@ void tst_QTextTable::QTBUG31330_renderBackground() } #endif +void tst_QTextTable::checkBorderAttributes_data() +{ + QTest::addColumn("html"); + QTest::addColumn("topBorderWidth"); + QTest::addColumn("bottomBorderWidth"); + QTest::addColumn("leftBorderWidth"); + QTest::addColumn("rightBorderWidth"); + QTest::addColumn("topBorderStyle"); + QTest::addColumn("bottomBorderStyle"); + QTest::addColumn("leftBorderStyle"); + QTest::addColumn("rightBorderStyle"); + QTest::addColumn("topBorderBrush"); + QTest::addColumn("bottomBorderBrush"); + QTest::addColumn("leftBorderBrush"); + QTest::addColumn("rightBorderBrush"); + + const QString tableHtmlStart = QStringLiteral("" + "
Foo
" + "
OneTwo
ThreeFour
"); + QTest::newRow("1px-solid-colors") + << QString("%1" + "td {" + "border-top: 1px solid red;" + "border-bottom: 1px solid blue;" + "border-left: 1px solid green;" + "border-right: 1px solid yellow;" + "}" + "%2").arg(tableHtmlStart).arg(tableHtmlEnd) + << 1.0 << 1.0 << 1.0 << 1.0 + << QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Solid + << QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Solid + << QBrush(Qt::red) << QBrush(Qt::blue) << QBrush(Qt::darkGreen) << QBrush(Qt::yellow); + QTest::newRow("MixedWidth-solid-colors") + << QString("%1" + "td {" + "border-top: 1px solid red;" + "border-bottom: 2px solid blue;" + "border-left: 3px solid green;" + "border-right: 4px solid yellow;" + "}" + "%2").arg(tableHtmlStart).arg(tableHtmlEnd) + << 1.0 << 2.0 << 3.0 << 4.0 + << QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Solid + << QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Solid + << QBrush(Qt::red) << QBrush(Qt::blue) << QBrush(Qt::darkGreen) << QBrush(Qt::yellow); + QTest::newRow("MixedWidth-MixedStyle-colors") + << QString("%1" + "td {" + "border-top: 1px solid red;" + "border-bottom: 2px dotted blue;" + "border-left: 3px dashed green;" + "border-right: 4px inset yellow;" + "}" + "%2").arg(tableHtmlStart).arg(tableHtmlEnd) + << 1.0 << 2.0 << 3.0 << 4.0 + << QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Dotted + << QTextFrameFormat::BorderStyle_Dashed << QTextFrameFormat::BorderStyle_Inset + << QBrush(Qt::red) << QBrush(Qt::blue) << QBrush(Qt::darkGreen) << QBrush(Qt::yellow); +} + +void tst_QTextTable::checkBorderAttributes() +{ + QFETCH(QString, html); + QFETCH(qreal, topBorderWidth); + QFETCH(qreal, bottomBorderWidth); + QFETCH(qreal, leftBorderWidth); + QFETCH(qreal, rightBorderWidth); + QFETCH(QTextFrameFormat::BorderStyle, topBorderStyle); + QFETCH(QTextFrameFormat::BorderStyle, bottomBorderStyle); + QFETCH(QTextFrameFormat::BorderStyle, leftBorderStyle); + QFETCH(QTextFrameFormat::BorderStyle, rightBorderStyle); + QFETCH(QBrush, topBorderBrush); + QFETCH(QBrush, bottomBorderBrush); + QFETCH(QBrush, leftBorderBrush); + QFETCH(QBrush, rightBorderBrush); + + QTextDocument doc; + doc.setHtml(html); + QTextCursor cursor(doc.firstBlock()); + cursor.movePosition(QTextCursor::Right); + + QTextTable *currentTable = cursor.currentTable(); + QVERIFY(currentTable); + for (int row = 0; row < 2; row++) { + for (int column = 0; column < 2; column++) { + QTextTableCell cell = currentTable->cellAt(row, column); + QTextCharFormat cellFormat = cell.format(); + QCOMPARE(cellFormat.doubleProperty(QTextFormat::TableCellTopBorder), topBorderWidth); + QCOMPARE(cellFormat.doubleProperty(QTextFormat::TableCellBottomBorder), bottomBorderWidth); + QCOMPARE(cellFormat.doubleProperty(QTextFormat::TableCellLeftBorder), leftBorderWidth); + QCOMPARE(cellFormat.doubleProperty(QTextFormat::TableCellRightBorder), rightBorderWidth); + QCOMPARE(cellFormat.property(QTextFormat::TableCellTopBorderStyle), topBorderStyle); + QCOMPARE(cellFormat.property(QTextFormat::TableCellBottomBorderStyle), bottomBorderStyle); + QCOMPARE(cellFormat.property(QTextFormat::TableCellLeftBorderStyle), leftBorderStyle); + QCOMPARE(cellFormat.property(QTextFormat::TableCellRightBorderStyle), rightBorderStyle); + QCOMPARE(cellFormat.brushProperty(QTextFormat::TableCellTopBorderBrush), topBorderBrush); + QCOMPARE(cellFormat.brushProperty(QTextFormat::TableCellBottomBorderBrush), bottomBorderBrush); + QCOMPARE(cellFormat.brushProperty(QTextFormat::TableCellLeftBorderBrush), leftBorderBrush); + QCOMPARE(cellFormat.brushProperty(QTextFormat::TableCellRightBorderBrush), rightBorderBrush); + } + } +} + QTEST_MAIN(tst_QTextTable) #include "tst_qtexttable.moc" -- cgit v1.2.3 From dcdfb6908db0f83cbc4e550859f56ee58a6b3420 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Wed, 14 Aug 2019 08:05:53 +0200 Subject: Remove workaround for compilers not supporting thread_local With C++11, all compilers support thread_local, which replaces the non- standardized __thread attribute as a storage class. The storage class was specifically introduced so that applications do not have to deal with pthread APIs for TLS key management. We still need to have some of that logic for adopting foreign threads, but we can rely on thread_local so that we get a fast implementation of QThread::currentThread() on all platforms. Change-Id: Iba2b35d014044c4ab317a0e127c5d1f1fa4ecd4a Reviewed-by: Marc Mutz Reviewed-by: Lars Knoll --- src/corelib/thread/qthread_unix.cpp | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 38e9c1c3ec..cb3c0d6bb1 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -108,20 +108,8 @@ Q_STATIC_ASSERT(sizeof(pthread_t) <= sizeof(Qt::HANDLE)); enum { ThreadPriorityResetFlag = 0x80000000 }; -#if defined(Q_OS_LINUX) && defined(__GLIBC__) && (defined(Q_CC_GNU) || defined(Q_CC_INTEL)) && !defined(QT_LINUXBASE) -/* LSB doesn't have __thread, https://lsbbugs.linuxfoundation.org/show_bug.cgi?id=993 */ -#define HAVE_TLS -#endif -#if defined(Q_CC_XLC) || defined (Q_CC_SUN) -#define HAVE_TLS -#endif -#if defined(Q_OS_RTEMS) -#define HAVE_TLS -#endif -#ifdef HAVE_TLS -static __thread QThreadData *currentThreadData = 0; -#endif +static thread_local QThreadData *currentThreadData = 0; static pthread_once_t current_thread_data_once = PTHREAD_ONCE_INIT; static pthread_key_t current_thread_data_key; @@ -182,28 +170,19 @@ Q_DESTRUCTOR_FUNCTION(destroy_current_thread_data_key) // Utility functions for getting, setting and clearing thread specific data. static QThreadData *get_thread_data() { -#ifdef HAVE_TLS return currentThreadData; -#else - pthread_once(¤t_thread_data_once, create_current_thread_data_key); - return reinterpret_cast(pthread_getspecific(current_thread_data_key)); -#endif } static void set_thread_data(QThreadData *data) { -#ifdef HAVE_TLS currentThreadData = data; -#endif pthread_once(¤t_thread_data_once, create_current_thread_data_key); pthread_setspecific(current_thread_data_key, data); } static void clear_thread_data() { -#ifdef HAVE_TLS currentThreadData = 0; -#endif pthread_setspecific(current_thread_data_key, 0); } -- cgit v1.2.3 From 8052755fd7581d70802f651d88b7af8447432d75 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Thu, 8 Aug 2019 16:12:46 +0200 Subject: Add means to configure HTTP/2 protocol handler Similar to TLS configuration that we can use on QNetworkRequest, we can configure different options in our HTTP/2 handling by providing QNetworkAccessManager with h2 configuration. Previously, it was only possible internally in our auto-test - a hack with QObject's properties and a private class. Now it's time to provide a public API for this. [ChangeLog][QtNetwork][QNetworkRequest] Add an ability to configure HTTP/2 protocol Change-Id: I80266a74f6dcdfabb7fc05ed1dce17897bcda886 Reviewed-by: Timur Pocheptsov --- src/network/access/access.pri | 6 +- src/network/access/http2/http2frames.cpp | 4 +- src/network/access/http2/http2protocol.cpp | 114 ++----- src/network/access/http2/http2protocol_p.h | 64 +--- src/network/access/qhttp2configuration.cpp | 343 +++++++++++++++++++++ src/network/access/qhttp2configuration.h | 99 ++++++ src/network/access/qhttp2protocolhandler.cpp | 44 +-- src/network/access/qhttp2protocolhandler_p.h | 25 +- src/network/access/qhttpnetworkconnection.cpp | 11 +- src/network/access/qhttpnetworkconnection_p.h | 8 +- .../access/qhttpnetworkconnectionchannel.cpp | 6 +- src/network/access/qhttpthreaddelegate.cpp | 4 +- src/network/access/qhttpthreaddelegate_p.h | 3 +- src/network/access/qnetworkaccessmanager.cpp | 3 +- src/network/access/qnetworkreplyhttpimpl.cpp | 6 +- src/network/access/qnetworkrequest.cpp | 58 +++- src/network/access/qnetworkrequest.h | 4 + tests/auto/network/access/http2/http2srv.cpp | 6 +- tests/auto/network/access/http2/http2srv.h | 11 +- tests/auto/network/access/http2/tst_http2.cpp | 68 ++-- 20 files changed, 644 insertions(+), 243 deletions(-) create mode 100644 src/network/access/qhttp2configuration.cpp create mode 100644 src/network/access/qhttp2configuration.h diff --git a/src/network/access/access.pri b/src/network/access/access.pri index 8a92308f12..87fb82b1a7 100644 --- a/src/network/access/access.pri +++ b/src/network/access/access.pri @@ -24,7 +24,8 @@ HEADERS += \ access/qabstractnetworkcache.h \ access/qnetworkfile_p.h \ access/qhsts_p.h \ - access/qhstspolicy.h + access/qhstspolicy.h \ + access/qhttp2configuration.h SOURCES += \ access/qnetworkaccessauthenticationmanager.cpp \ @@ -44,7 +45,8 @@ SOURCES += \ access/qabstractnetworkcache.cpp \ access/qnetworkfile.cpp \ access/qhsts.cpp \ - access/qhstspolicy.cpp + access/qhstspolicy.cpp \ + access/qhttp2configuration.cpp qtConfig(ftp) { HEADERS += \ diff --git a/src/network/access/http2/http2frames.cpp b/src/network/access/http2/http2frames.cpp index e695b4dd9e..ce33505683 100644 --- a/src/network/access/http2/http2frames.cpp +++ b/src/network/access/http2/http2frames.cpp @@ -305,7 +305,7 @@ FrameStatus FrameReader::read(QAbstractSocket &socket) return status; } - if (Http2PredefinedParameters::maxFrameSize < frame.payloadSize()) + if (Http2PredefinedParameters::maxPayloadSize < frame.payloadSize()) return FrameStatus::sizeError; frame.buffer.resize(frame.payloadSize() + frameHeaderSize); @@ -388,7 +388,7 @@ void FrameWriter::setPayloadSize(quint32 size) auto &buffer = frame.buffer; Q_ASSERT(buffer.size() >= frameHeaderSize); - Q_ASSERT(size < maxPayloadSize); + Q_ASSERT(size <= maxPayloadSize); buffer[0] = size >> 16; buffer[1] = size >> 8; diff --git a/src/network/access/http2/http2protocol.cpp b/src/network/access/http2/http2protocol.cpp index 0be72042c6..0290f9ac00 100644 --- a/src/network/access/http2/http2protocol.cpp +++ b/src/network/access/http2/http2protocol.cpp @@ -43,6 +43,8 @@ #include "private/qhttpnetworkrequest_p.h" #include "private/qhttpnetworkreply_p.h" +#include + #include #include @@ -62,88 +64,25 @@ const char Http2clientPreface[clientPrefaceLength] = 0x2e, 0x30, 0x0d, 0x0a, 0x0d, 0x0a, 0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a}; -// TODO: (in 5.11) - remove it! -const char *http2ParametersPropertyName = "QT_HTTP2_PARAMETERS_PROPERTY"; - -ProtocolParameters::ProtocolParameters() -{ - settingsFrameData[Settings::INITIAL_WINDOW_SIZE_ID] = qtDefaultStreamReceiveWindowSize; - settingsFrameData[Settings::ENABLE_PUSH_ID] = 0; -} - -bool ProtocolParameters::validate() const +Frame configurationToSettingsFrame(const QHttp2Configuration &config) { - // 0. Huffman/indexing: any values are valid and allowed. - - // 1. Session receive window size (client side): HTTP/2 starts from the - // default value of 64Kb, if a client code tries to set lesser value, - // the delta would become negative, but this is not allowed. - if (maxSessionReceiveWindowSize < qint32(defaultSessionWindowSize)) { - qCWarning(QT_HTTP2, "Session receive window must be at least 65535 bytes"); - return false; - } - - // 2. HEADER_TABLE_SIZE: we do not validate HEADER_TABLE_SIZE, considering - // all values as valid. RFC 7540 and 7541 do not provide any lower/upper - // limits. If it's 0 - we do not index anything, if it's too huge - a user - // who provided such a value can potentially have a huge memory footprint, - // up to them to decide. - - // 3. SETTINGS_ENABLE_PUSH: RFC 7540, 6.5.2, a value other than 0 or 1 will - // be treated by our peer as a PROTOCOL_ERROR. - if (settingsFrameData.contains(Settings::ENABLE_PUSH_ID) - && settingsFrameData[Settings::ENABLE_PUSH_ID] > 1) { - qCWarning(QT_HTTP2, "SETTINGS_ENABLE_PUSH can be only 0 or 1"); - return false; - } - - // 4. SETTINGS_MAX_CONCURRENT_STREAMS : RFC 7540 recommends 100 as the lower - // limit, says nothing about the upper limit. The RFC allows 0, but this makes - // no sense to us at all: there is no way a user can change this later and - // we'll not be able to get any responses on such a connection. - if (settingsFrameData.contains(Settings::MAX_CONCURRENT_STREAMS_ID) - && !settingsFrameData[Settings::MAX_CONCURRENT_STREAMS_ID]) { - qCWarning(QT_HTTP2, "MAX_CONCURRENT_STREAMS must be a positive number"); - return false; - } - - // 5. SETTINGS_INITIAL_WINDOW_SIZE. - if (settingsFrameData.contains(Settings::INITIAL_WINDOW_SIZE_ID)) { - const quint32 value = settingsFrameData[Settings::INITIAL_WINDOW_SIZE_ID]; - // RFC 7540, 6.5.2 (the upper limit). The lower limit is our own - we send - // SETTINGS frame only once and will not be able to change this 0, thus - // we'll suspend all streams. - if (!value || value > quint32(maxSessionReceiveWindowSize)) { - qCWarning(QT_HTTP2, "INITIAL_WINDOW_SIZE must be in the range " - "(0, 2^31-1]"); - return false; - } - } - - // 6. SETTINGS_MAX_FRAME_SIZE: RFC 7540, 6.5.2, a value outside of the range - // [2^14-1, 2^24-1] will be treated by our peer as a PROTOCOL_ERROR. - if (settingsFrameData.contains(Settings::MAX_FRAME_SIZE_ID)) { - const quint32 value = settingsFrameData[Settings::INITIAL_WINDOW_SIZE_ID]; - if (value < maxFrameSize || value > maxPayloadSize) { - qCWarning(QT_HTTP2, "MAX_FRAME_SIZE must be in the range [2^14, 2^24-1]"); - return false; - } - } - - // For SETTINGS_MAX_HEADER_LIST_SIZE RFC 7540 does not provide any specific - // numbers. It's clear, if a value is too small, no header can ever be sent - // by our peer at all. The default value is unlimited and we normally do not - // change this. - // - // Note: the size is calculated as the length of uncompressed (no HPACK) - // name + value + 32 bytes. - - return true; + // 6.5 SETTINGS + FrameWriter builder(FrameType::SETTINGS, FrameFlag::EMPTY, connectionStreamID); + // Server push: + builder.append(Settings::ENABLE_PUSH_ID); + builder.append(int(config.serverPushEnabled())); + // Stream receive window size: + builder.append(Settings::INITIAL_WINDOW_SIZE_ID); + builder.append(config.streamReceiveWindowSize()); + + // TODO: Max frame size; in future, if the need + // is proven, we can also set decoding table size + // and header list size. For now, defaults suffice. + return builder.outboundFrame(); } -QByteArray ProtocolParameters::settingsFrameToBase64() const +QByteArray settingsFrameToBase64(const Frame &frame) { - Frame frame(settingsFrame()); // SETTINGS frame's payload consists of pairs: // 2-byte-identifier | 4-byte-value == multiple of 6. Q_ASSERT(frame.payloadSize() && !(frame.payloadSize() % 6)); @@ -157,20 +96,7 @@ QByteArray ProtocolParameters::settingsFrameToBase64() const return wrapper.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); } -Frame ProtocolParameters::settingsFrame() const -{ - // 6.5 SETTINGS - FrameWriter builder(FrameType::SETTINGS, FrameFlag::EMPTY, connectionStreamID); - for (auto it = settingsFrameData.cbegin(), end = settingsFrameData.cend(); - it != end; ++it) { - builder.append(it.key()); - builder.append(it.value()); - } - - return builder.outboundFrame(); -} - -void ProtocolParameters::addProtocolUpgradeHeaders(QHttpNetworkRequest *request) const +void appendProtocolUpgradeHeaders(const QHttp2Configuration &config, QHttpNetworkRequest *request) { Q_ASSERT(request); // RFC 2616, 14.10 @@ -184,8 +110,10 @@ void ProtocolParameters::addProtocolUpgradeHeaders(QHttpNetworkRequest *request) request->setHeaderField("Connection", value); // This we just (re)write. request->setHeaderField("Upgrade", "h2c"); + + const Frame frame(configurationToSettingsFrame(config)); // This we just (re)write. - request->setHeaderField("HTTP2-Settings", settingsFrameToBase64()); + request->setHeaderField("HTTP2-Settings", settingsFrameToBase64(frame)); } void qt_error(quint32 errorCode, QNetworkReply::NetworkError &error, diff --git a/src/network/access/http2/http2protocol_p.h b/src/network/access/http2/http2protocol_p.h index 7142d6f1fa..b0af5aa919 100644 --- a/src/network/access/http2/http2protocol_p.h +++ b/src/network/access/http2/http2protocol_p.h @@ -55,12 +55,14 @@ #include #include #include +#include // Different HTTP/2 constants/values as defined by RFC 7540. QT_BEGIN_NAMESPACE class QHttpNetworkRequest; +class QHttp2Configuration; class QHttpNetworkReply; class QByteArray; class QString; @@ -118,13 +120,19 @@ enum Http2PredefinedParameters connectionStreamID = 0, // HTTP/2, 5.1.1 frameHeaderSize = 9, // HTTP/2, 4.1 - // It's our max frame size we send in SETTINGS frame, - // it's also the default one and we also use it to later - // validate incoming frames: - maxFrameSize = 16384, // HTTP/2 6.5.2 + // The initial allowed payload size. We would use it as an + // upper limit for a frame payload we send, until our peer + // updates us with a larger SETTINGS_MAX_FRAME_SIZE. - defaultSessionWindowSize = 65535, // HTTP/2 6.5.2 + // The initial maximum payload size that an HTTP/2 frame + // can contain is 16384. It's also the minimal size that + // can be advertised via 'SETTINGS' frames. A real frame + // can have a payload smaller than 16384. + minPayloadLimit = 16384, // HTTP/2 6.5.2 + // The maximum allowed payload size. maxPayloadSize = (1 << 24) - 1, // HTTP/2 6.5.2 + + defaultSessionWindowSize = 65535, // HTTP/2 6.5.2 // Using 1000 (rather arbitrarily), just to // impose *some* upper limit: maxPeerConcurrentStreams = 1000, @@ -145,48 +153,9 @@ const quint32 lastValidStreamID((quint32(1) << 31) - 1); // HTTP/2, 5.1.1 const qint32 maxSessionReceiveWindowSize((quint32(1) << 31) - 1); const qint32 qtDefaultStreamReceiveWindowSize = maxSessionReceiveWindowSize / maxConcurrentStreams; -// The class ProtocolParameters allows client code to customize HTTP/2 protocol -// handler, if needed. Normally, we use our own default parameters (see below). -// In 5.10 we can also use setProperty/property on a QNAM object to pass the -// non-default values to the protocol handler. In 5.11 this will probably become -// a public API. - -using RawSettings = QMap; - -struct Q_AUTOTEST_EXPORT ProtocolParameters -{ - ProtocolParameters(); - - bool validate() const; - QByteArray settingsFrameToBase64() const; - struct Frame settingsFrame() const; - void addProtocolUpgradeHeaders(QHttpNetworkRequest *request) const; - - // HPACK: - // TODO: for now we ignore them (fix it for 5.11, would require changes in HPACK) - bool useHuffman = true; - bool indexStrings = true; - - // This parameter is not negotiated via SETTINGS frames, so we have it - // as a member and will convey it to our peer as a WINDOW_UPDATE frame. - // Note, some servers do not accept our WINDOW_UPDATE from the default - // 64 KB to the possible maximum. Let's use a half of it: - qint32 maxSessionReceiveWindowSize = Http2::maxSessionReceiveWindowSize / 2; - - // This is our default SETTINGS frame: - // - // SETTINGS_INITIAL_WINDOW_SIZE: (2^31 - 1) / 100 - // SETTINGS_ENABLE_PUSH: 0. - // - // Note, whenever we skip some value in our SETTINGS frame, our peer - // will assume the defaults recommended by RFC 7540, which in general - // are good enough, although we (and most browsers) prefer to work - // with larger window sizes. - RawSettings settingsFrameData; -}; - -// TODO: remove in 5.11 -extern const Q_AUTOTEST_EXPORT char *http2ParametersPropertyName; +struct Frame configurationToSettingsFrame(const QHttp2Configuration &configuration); +QByteArray settingsFrameToBase64(const Frame &settingsFrame); +void appendProtocolUpgradeHeaders(const QHttp2Configuration &configuration, QHttpNetworkRequest *request); extern const Q_AUTOTEST_EXPORT char Http2clientPreface[clientPrefaceLength]; @@ -235,6 +204,5 @@ Q_DECLARE_LOGGING_CATEGORY(QT_HTTP2) QT_END_NAMESPACE Q_DECLARE_METATYPE(Http2::Settings) -Q_DECLARE_METATYPE(Http2::ProtocolParameters) #endif diff --git a/src/network/access/qhttp2configuration.cpp b/src/network/access/qhttp2configuration.cpp new file mode 100644 index 0000000000..14c9d6dc29 --- /dev/null +++ b/src/network/access/qhttp2configuration.cpp @@ -0,0 +1,343 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhttp2configuration.h" + +#include "private/http2protocol_p.h" +#include "private/hpack_p.h" + +#include "qdebug.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QHttp2Configuration + \brief The QHttp2Configuration class controls HTTP/2 parameters and settings + \since 5.14 + + \reentrant + \inmodule QtNetwork + \ingroup network + \ingroup shared + + QHttp2Configuration controls HTTP/2 parameters and settings that + QNetworkAccessManager will use to send requests and process responses + when the HTTP/2 protocol is enabled. + + The HTTP/2 parameters that QHttp2Configuration currently supports include: + + \list + \li The session window size for connection-level flow control. + Will be sent to a remote peer when needed as 'WINDOW_UPDATE' + frames on the stream with an identifier 0. + \li The stream receiving window size for stream-level flow control. + Sent as 'SETTINGS_INITIAL_WINDOW_SIZE' parameter in the initial + SETTINGS frame and, when needed, 'WINDOW_UPDATE' frames will be + sent on streams that QNetworkAccessManager opens. + \li The maximum frame size. This parameter limits the maximum payload + a frame coming from the remote peer can have. Sent by QNetworkAccessManager + as 'SETTINGS_MAX_FRAME_SIZE' parameter in the initial 'SETTINGS' + frame. + \li The server push. Allows to enable or disable server push. Sent + as 'SETTINGS_ENABLE_PUSH' parameter in the initial 'SETTINGS' + frame. + \endlist + + The QHttp2Configuration class also controls some of the parameters + affecting the header compression algorithm (HPACK). They include: + + \list + \li Huffman string compression. + \li Indexing strings. + \endlist + + \note The configuration must be set before the first request + was sent to a given host (and thus an HTTP/2 session established). + + \note Details about flow control, server push and 'SETTINGS' + can be found in \l {https://httpwg.org/specs/rfc7540.html}{RFC 7540}. + Different modes and parameters of the HPACK compression algorithm + are described in \l {https://httpwg.org/specs/rfc7541.html}{RFC 7541}. + + \sa QNetworkRequest::setHttp2Configuration(), QNetworkRequest::http2Configuration(), QNetworkAccessManager +*/ + +class QHttp2ConfigurationPrivate : public QSharedData +{ +public: + unsigned sessionWindowSize = Http2::defaultSessionWindowSize; + // The size below is quite a limiting default value, QNetworkRequest + // by default sets a larger number, an application can change this using + // QNetworkRequest::setHttp2Configuration. + unsigned streamWindowSize = Http2::defaultSessionWindowSize; + + unsigned maxFrameSize = Http2::minPayloadLimit; // Initial (default) value of 16Kb. + + bool pushEnabled = false; + // TODO: for now those two below are noop. + bool huffmanCompressionEnabled = true; + bool indexingEnabled = true; +}; + +/*! + Default constructs a QHttp2Configuration object. + + Such a configuration has the following values: + \list + \li Server push is disabled + \li Huffman string compression is enabled + \li String indexing is enabled + \li Window size for connection-level flow control is 65535 octets + \li Window size for stream-level flow control is 65535 octets + \li Frame size is 16384 octets + \endlist +*/ +QHttp2Configuration::QHttp2Configuration() + : d(new QHttp2ConfigurationPrivate) +{ +} + +/*! + Copy-constructs this QHttp2Configuration. +*/ +QHttp2Configuration::QHttp2Configuration(const QHttp2Configuration &) = default; + +/*! + Move-constructs this QHttp2Configuration from \a other +*/ +QHttp2Configuration::QHttp2Configuration(QHttp2Configuration &&other) noexcept +{ + swap(other); +} + +/*! + Copy-assigns to this QHttp2Configuration. +*/ +QHttp2Configuration &QHttp2Configuration::operator=(const QHttp2Configuration &) = default; + +/*! + Move-assigns to this QHttp2Configuration. +*/ +QHttp2Configuration &QHttp2Configuration::operator=(QHttp2Configuration &&) noexcept = default; + +/*! + Destructor. +*/ +QHttp2Configuration::~QHttp2Configuration() +{ +} + +/*! + If \a enable is \c true, a remote server can potentially + use server push to send reponses in advance. + + \sa serverPushEnabled +*/ +void QHttp2Configuration::setServerPushEnabled(bool enable) +{ + d->pushEnabled = enable; +} + +/*! + Returns true if server push was enabled. + + \note By default, QNetworkAccessManager disables server + push via the 'SETTINGS' frame. + + \sa setServerPushEnabled +*/ +bool QHttp2Configuration::serverPushEnabled() const +{ + return d->pushEnabled; +} + +/*! + If \a enable is \c true, HPACK compression will additionally + compress string using the Huffman coding. Enabled by default. + + \note This parameter only affects 'HEADERS' frames that + QNetworkAccessManager is sending. + + \sa huffmanCompressionEnabled +*/ +void QHttp2Configuration::setHuffmanCompressionEnabled(bool enable) +{ + d->huffmanCompressionEnabled = enable; +} + +/*! + Returns \c true if the Huffman coding in HPACK is enabled. + + \sa setHuffmanCompressionEnabled +*/ +bool QHttp2Configuration::huffmanCompressionEnabled() const +{ + return d->huffmanCompressionEnabled; +} + +/*! + If \a enable is \c true, HPACK compression will index strings + in its dynamic compression table. Enabled by default. + + \note This setting only has an affect on how QNetworkAccessManager + sending 'HEADERS' frames. + + \sa stringIndexingEnabled +*/ +void QHttp2Configuration::setStringIndexingEnabled(bool enable) +{ + d->indexingEnabled = enable; +} + +/*! + Returns \true if HPACK compression is indexing strings. + + \sa setStringIndexingEnabled +*/ +bool QHttp2Configuration::stringIndexingEnabled() const +{ + return d->indexingEnabled; +} + +/*! + Sets the window size for connection-level flow control. + \a size cannot be 0 and must not exceed 2147483647 octets. + + \sa sessionReceiveWindowSize +*/ +bool QHttp2Configuration::setSessionReceiveWindowSize(unsigned size) +{ + if (!size || size > Http2::maxSessionReceiveWindowSize) { // RFC-7540, 6.9 + qCWarning(QT_HTTP2) << "Invalid session window size"; + return false; + } + + d->sessionWindowSize = size; + return true; +} + +/*! + Returns the window size for connection-level flow control. + The default value QNetworkAccessManager will be using is + 2147483647 octets. +*/ +unsigned QHttp2Configuration::sessionReceiveWindowSize() const +{ + return d->sessionWindowSize; +} + +/*! + Sets the window size for stream-level flow control. + \a size cannot be 0 and must not exceed 2147483647 octets. + + \sa streamReceiveWindowSize + */ +bool QHttp2Configuration::setStreamReceiveWindowSize(unsigned size) +{ + if (!size || size > Http2::maxSessionReceiveWindowSize) { // RFC-7540, 6.9 + qCWarning(QT_HTTP2) << "Invalid stream window size"; + return false; + } + + d->streamWindowSize = size; + return true; +} + +/*! + Returns the window size for stream-level flow control. + The default value QNetworkAccessManager will be using is + 21474836 octets. +*/ +unsigned QHttp2Configuration::streamReceiveWindowSize() const +{ + return d->streamWindowSize; +} + +/*! + Sets the maximum frame size that QNetworkAccessManager + will advertise to the server when sending its initial SETTINGS frame. + \note While this \a size is required to be within a range between + 16384 and 16777215 inclusive, the actual payload size in frames + that carry payload maybe be less than 16384. +*/ +bool QHttp2Configuration::setMaxFrameSize(unsigned size) +{ + if (size < Http2::minPayloadLimit || size > Http2::maxPayloadSize) { + qCWarning(QT_HTTP2) << "Maximum frame size to advertise is invalid"; + return false; + } + + d->maxFrameSize = size; + return true; +} + +/*! + The maximum payload size that HTTP/2 frames can + have. The default (initial) value is 16384 octets. +*/ +unsigned QHttp2Configuration::maxFrameSize() const +{ + return d->maxFrameSize; +} + +/*! + Swaps this configuration with the \a other configuration. +*/ +void QHttp2Configuration::swap(QHttp2Configuration &other) noexcept +{ + d.swap(other.d); +} + +/*! + Returns \c true if \a lhs and \a rhs have the same set of HTTP/2 + parameters. +*/ +bool operator==(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs) +{ + if (lhs.d == rhs.d) + return true; + + return lhs.d->pushEnabled == rhs.d->pushEnabled + && lhs.d->huffmanCompressionEnabled == rhs.d->huffmanCompressionEnabled + && lhs.d->indexingEnabled == rhs.d->indexingEnabled + && lhs.d->sessionWindowSize == rhs.d->sessionWindowSize + && lhs.d->streamWindowSize == rhs.d->streamWindowSize; +} + +QT_END_NAMESPACE diff --git a/src/network/access/qhttp2configuration.h b/src/network/access/qhttp2configuration.h new file mode 100644 index 0000000000..2a5e8c9341 --- /dev/null +++ b/src/network/access/qhttp2configuration.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHTTP2CONFIGURATION_H +#define QHTTP2CONFIGURATION_H + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QHttp2ConfigurationPrivate; +class Q_NETWORK_EXPORT QHttp2Configuration +{ + friend Q_NETWORK_EXPORT bool operator==(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs); + +public: + QHttp2Configuration(); + QHttp2Configuration(const QHttp2Configuration &other); + QHttp2Configuration(QHttp2Configuration &&other) noexcept; + QHttp2Configuration &operator = (const QHttp2Configuration &other); + QHttp2Configuration &operator = (QHttp2Configuration &&other) noexcept; + + ~QHttp2Configuration(); + + void setServerPushEnabled(bool enable); + bool serverPushEnabled() const; + + void setHuffmanCompressionEnabled(bool enable); + bool huffmanCompressionEnabled() const; + + void setStringIndexingEnabled(bool enable); + bool stringIndexingEnabled() const; + + bool setSessionReceiveWindowSize(unsigned size); + unsigned sessionReceiveWindowSize() const; + + bool setStreamReceiveWindowSize(unsigned size); + unsigned streamReceiveWindowSize() const; + + bool setMaxFrameSize(unsigned size); + unsigned maxFrameSize() const; + + void swap(QHttp2Configuration &other) noexcept; + +private: + + QSharedDataPointer d; +}; + +Q_DECLARE_SHARED(QHttp2Configuration) + +Q_NETWORK_EXPORT bool operator==(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs); + +inline bool operator!=(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs) +{ + return !(lhs == rhs); +} + +QT_END_NAMESPACE + +#endif // QHTTP2CONFIGURATION_H diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp index 0ece5b7179..b8a415000a 100644 --- a/src/network/access/qhttp2protocolhandler.cpp +++ b/src/network/access/qhttp2protocolhandler.cpp @@ -40,6 +40,7 @@ #include "qhttpnetworkconnection_p.h" #include "qhttp2protocolhandler_p.h" +#include "http2/http2frames_p.h" #include "http2/bitstreams_p.h" #include @@ -51,6 +52,8 @@ #include #include +#include + #ifndef QT_NO_NETWORKPROXY #include #endif @@ -172,30 +175,10 @@ QHttp2ProtocolHandler::QHttp2ProtocolHandler(QHttpNetworkConnectionChannel *chan Q_ASSERT(channel && m_connection); continuedFrames.reserve(20); - const ProtocolParameters params(m_connection->http2Parameters()); - Q_ASSERT(params.validate()); - - maxSessionReceiveWindowSize = params.maxSessionReceiveWindowSize; - - const RawSettings &data = params.settingsFrameData; - for (auto param = data.cbegin(), end = data.cend(); param != end; ++param) { - switch (param.key()) { - case Settings::INITIAL_WINDOW_SIZE_ID: - streamInitialReceiveWindowSize = param.value(); - break; - case Settings::ENABLE_PUSH_ID: - pushPromiseEnabled = param.value(); - break; - case Settings::HEADER_TABLE_SIZE_ID: - case Settings::MAX_CONCURRENT_STREAMS_ID: - case Settings::MAX_FRAME_SIZE_ID: - case Settings::MAX_HEADER_LIST_SIZE_ID: - // These other settings are just recommendations to our peer. We - // only check they are not crazy in ProtocolParameters::validate(). - default: - break; - } - } + const auto h2Config = m_connection->http2Parameters(); + maxSessionReceiveWindowSize = h2Config.sessionReceiveWindowSize(); + pushPromiseEnabled = h2Config.serverPushEnabled(); + streamInitialReceiveWindowSize = h2Config.streamReceiveWindowSize(); if (!channel->ssl && m_connection->connectionType() != QHttpNetworkConnection::ConnectionTypeHTTP2Direct) { // We upgraded from HTTP/1.1 to HTTP/2. channel->request was already sent @@ -422,20 +405,17 @@ bool QHttp2ProtocolHandler::sendClientPreface() return false; // 6.5 SETTINGS - const ProtocolParameters params(m_connection->http2Parameters()); - Q_ASSERT(params.validate()); - frameWriter.setOutboundFrame(params.settingsFrame()); + frameWriter.setOutboundFrame(Http2::configurationToSettingsFrame(m_connection->http2Parameters())); Q_ASSERT(frameWriter.outboundFrame().payloadSize()); if (!frameWriter.write(*m_socket)) return false; sessionReceiveWindowSize = maxSessionReceiveWindowSize; - // ProtocolParameters::validate does not allow maxSessionReceiveWindowSize - // to be smaller than defaultSessionWindowSize, so everything is OK here with - // 'delta': + // We only send WINDOW_UPDATE for the connection if the size differs from the + // default 64 KB: const auto delta = maxSessionReceiveWindowSize - Http2::defaultSessionWindowSize; - if (!sendWINDOW_UPDATE(Http2::connectionStreamID, delta)) + if (delta && !sendWINDOW_UPDATE(Http2::connectionStreamID, delta)) return false; prefaceSent = true; @@ -1069,7 +1049,7 @@ bool QHttp2ProtocolHandler::acceptSetting(Http2::Settings identifier, quint32 ne } if (identifier == Settings::MAX_FRAME_SIZE_ID) { - if (newValue < Http2::maxFrameSize || newValue > Http2::maxPayloadSize) { + if (newValue < Http2::minPayloadLimit || newValue > Http2::maxPayloadSize) { connectionError(PROTOCOL_ERROR, "SETTGINGS max frame size is out of range"); return false; } diff --git a/src/network/access/qhttp2protocolhandler_p.h b/src/network/access/qhttp2protocolhandler_p.h index b582123961..1943827e23 100644 --- a/src/network/access/qhttp2protocolhandler_p.h +++ b/src/network/access/qhttp2protocolhandler_p.h @@ -55,6 +55,8 @@ #include #include +#include + #include #include #include @@ -163,8 +165,9 @@ private: static const std::deque::size_type maxRecycledStreams; std::deque recycledStreams; - // Peer's max frame size. - quint32 maxFrameSize = Http2::maxFrameSize; + // Peer's max frame size (this min is the default value + // we start with, that can be updated by SETTINGS frame): + quint32 maxFrameSize = Http2::minPayloadLimit; Http2::FrameReader frameReader; Http2::Frame inboundFrame; @@ -176,28 +179,28 @@ private: // Control flow: - // This is how many concurrent streams our peer expects from us: - // 100 is the default value, can be updated by the server's SETTINGS - // frame(s): + // This is how many concurrent streams our peer allows us, 100 is the + // initial value, can be updated by the server's SETTINGS frame(s): quint32 maxConcurrentStreams = Http2::maxConcurrentStreams; // While we allow sending SETTTINGS_MAX_CONCURRENT_STREAMS to limit our peer, // it's just a hint and we do not actually enforce it (and we can continue // sending requests and creating streams while maxConcurrentStreams allows). - // This is the max value, we set it in a ctor from Http2::ProtocolParameters, - // it does not change after that. + // This is our (client-side) maximum possible receive window size, we set + // it in a ctor from QHttp2Configuration, it does not change after that. + // The default is 64Kb: qint32 maxSessionReceiveWindowSize = Http2::defaultSessionWindowSize; - // Our session receive window size, default is 64Kb. We'll update it from QNAM's - // Http2::ProtocolParameters. Signed integer since it can become negative + // Our session current receive window size, updated in a ctor from + // QHttp2Configuration. Signed integer since it can become negative // (it's still a valid window size). qint32 sessionReceiveWindowSize = Http2::defaultSessionWindowSize; // Our per-stream receive window size, default is 64 Kb, will be updated - // from QNAM's Http2::ProtocolParameters. Again, signed - can become negative. + // from QHttp2Configuration. Again, signed - can become negative. qint32 streamInitialReceiveWindowSize = Http2::defaultSessionWindowSize; // These are our peer's receive window sizes, they will be updated by the - // peer's SETTINGS and WINDOW_UPDATE frames. + // peer's SETTINGS and WINDOW_UPDATE frames, defaults presumed to be 64Kb. qint32 sessionSendWindowSize = Http2::defaultSessionWindowSize; qint32 streamInitialSendWindowSize = Http2::defaultSessionWindowSize; diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 1f1de478ea..13be1aa6b5 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -1456,21 +1456,16 @@ void QHttpNetworkConnection::setConnectionType(ConnectionType type) d->connectionType = type; } -Http2::ProtocolParameters QHttpNetworkConnection::http2Parameters() const +QHttp2Configuration QHttpNetworkConnection::http2Parameters() const { Q_D(const QHttpNetworkConnection); return d->http2Parameters; } -void QHttpNetworkConnection::setHttp2Parameters(const Http2::ProtocolParameters ¶ms) +void QHttpNetworkConnection::setHttp2Parameters(const QHttp2Configuration ¶ms) { Q_D(QHttpNetworkConnection); - if (params.validate()) { - d->http2Parameters = params; - } else { - qCWarning(QT_HTTP2) - << "invalid HTTP/2 parameters, falling back to defaults instead"; - } + d->http2Parameters = params; } // SSL support below diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h index 85d89f20c2..6808a0c0ac 100644 --- a/src/network/access/qhttpnetworkconnection_p.h +++ b/src/network/access/qhttpnetworkconnection_p.h @@ -57,6 +57,8 @@ #include #include +#include + #include #include #include @@ -142,8 +144,8 @@ public: ConnectionType connectionType(); void setConnectionType(ConnectionType type); - Http2::ProtocolParameters http2Parameters() const; - void setHttp2Parameters(const Http2::ProtocolParameters ¶ms); + QHttp2Configuration http2Parameters() const; + void setHttp2Parameters(const QHttp2Configuration ¶ms); #ifndef QT_NO_SSL void setSslConfiguration(const QSslConfiguration &config); @@ -294,7 +296,7 @@ public: QSharedPointer networkSession; #endif - Http2::ProtocolParameters http2Parameters; + QHttp2Configuration http2Parameters; QString peerVerifyName; // If network status monitoring is enabled, we activate connectionMonitor diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 3c9d53c5b5..716ea6c8b2 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -40,6 +40,7 @@ #include "qhttpnetworkconnectionchannel_p.h" #include "qhttpnetworkconnection_p.h" +#include "qhttp2configuration.h" #include "private/qnoncontiguousbytedevice_p.h" #include @@ -48,6 +49,7 @@ #include #include #include +#include #ifndef QT_NO_SSL # include @@ -947,9 +949,7 @@ void QHttpNetworkConnectionChannel::_q_connected() if (tryProtocolUpgrade) { // Let's augment our request with some magic headers and try to // switch to HTTP/2. - const Http2::ProtocolParameters params(connection->http2Parameters()); - Q_ASSERT(params.validate()); - params.addProtocolUpgradeHeaders(&request); + Http2::appendProtocolUpgradeHeaders(connection->http2Parameters(), &request); } sendRequest(); } diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp index acc551a7c9..1900397eab 100644 --- a/src/network/access/qhttpthreaddelegate.cpp +++ b/src/network/access/qhttpthreaddelegate.cpp @@ -352,9 +352,9 @@ void QHttpThreadDelegate::startRequest() networkSession); #endif // QT_NO_BEARERMANAGEMENT if (connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2 - && http2Parameters.validate()) { + || connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) { httpConnection->setHttp2Parameters(http2Parameters); - } // else we ignore invalid parameters and use our own defaults. + } #ifndef QT_NO_SSL // Set the QSslConfiguration from this QNetworkRequest. if (ssl) diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h index 6184b39b30..355d1afc30 100644 --- a/src/network/access/qhttpthreaddelegate_p.h +++ b/src/network/access/qhttpthreaddelegate_p.h @@ -62,6 +62,7 @@ #include #include "qhttpnetworkrequest_p.h" #include "qhttpnetworkconnection_p.h" +#include "qhttp2configuration.h" #include #include #include "private/qnoncontiguousbytedevice_p.h" @@ -116,7 +117,7 @@ public: qint64 removedContentLength; QNetworkReply::NetworkError incomingErrorCode; QString incomingErrorDetail; - Http2::ProtocolParameters http2Parameters; + QHttp2Configuration http2Parameters; #ifndef QT_NO_BEARERMANAGEMENT QSharedPointer networkSession; #endif diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 29192ae7b0..fdc3cd3b3a 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -70,6 +70,7 @@ #include "QtNetwork/private/qauthenticator_p.h" #include "QtNetwork/qsslconfiguration.h" #include "QtNetwork/qnetworkconfigmanager.h" +#include "QtNetwork/private/http2protocol_p.h" #if QT_CONFIG(http) #include "qhttpmultipart.h" @@ -489,6 +490,7 @@ QNetworkAccessManager::QNetworkAccessManager(QObject *parent) qRegisterMetaType >(); Q_D(QNetworkAccessManager); + if (QNetworkStatusMonitor::isEnabled()) { connect(&d->statusMonitor, SIGNAL(onlineStateChanged(bool)), SLOT(_q_onlineStateChanged(bool))); @@ -1178,7 +1180,6 @@ QSharedPointer QNetworkAccessManagerPrivate::getNetworkSession( #endif // QT_NO_BEARERMANAGEMENT - #ifndef QT_NO_SSL /*! \since 5.2 diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index b9651b35d2..12dfb1c269 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -797,10 +797,8 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq // Create the HTTP thread delegate QHttpThreadDelegate *delegate = new QHttpThreadDelegate; - // Propagate Http/2 settings if any - const QVariant blob(manager->property(Http2::http2ParametersPropertyName)); - if (blob.isValid() && blob.canConvert()) - delegate->http2Parameters = blob.value(); + // Propagate Http/2 settings: + delegate->http2Parameters = request.http2Configuration(); #ifndef QT_NO_BEARERMANAGEMENT if (!QNetworkStatusMonitor::isEnabled()) delegate->networkSession = managerPrivate->getNetworkSession(); diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index 37f64c3f52..e3976db642 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -42,6 +42,8 @@ #include "qplatformdefs.h" #include "qnetworkcookie.h" #include "qsslconfiguration.h" +#include "qhttp2configuration.h" +#include "private/http2protocol_p.h" #include "QtCore/qshareddata.h" #include "QtCore/qlocale.h" #include "QtCore/qdatetime.h" @@ -445,6 +447,7 @@ public: sslConfiguration = new QSslConfiguration(*other.sslConfiguration); #endif peerVerifyName = other.peerVerifyName; + h2Configuration = other.h2Configuration; } inline bool operator==(const QNetworkRequestPrivate &other) const @@ -454,7 +457,8 @@ public: rawHeaders == other.rawHeaders && attributes == other.attributes && maxRedirectsAllowed == other.maxRedirectsAllowed && - peerVerifyName == other.peerVerifyName; + peerVerifyName == other.peerVerifyName && + h2Configuration == other.h2Configuration; // don't compare cookedHeaders } @@ -465,6 +469,7 @@ public: #endif int maxRedirectsAllowed; QString peerVerifyName; + QHttp2Configuration h2Configuration; }; /*! @@ -476,6 +481,13 @@ public: QNetworkRequest::QNetworkRequest() : d(new QNetworkRequestPrivate) { + // Initial values proposed by RFC 7540 are quite draconian, + // so unless an application will set its own parameters, we + // make stream window size larger and increase (via WINDOW_UPDATE) + // the session window size. These are our 'defaults': + d->h2Configuration.setStreamReceiveWindowSize(Http2::qtDefaultStreamReceiveWindowSize); + d->h2Configuration.setSessionReceiveWindowSize(Http2::maxSessionReceiveWindowSize); + d->h2Configuration.setServerPushEnabled(false); } /*! @@ -835,6 +847,50 @@ void QNetworkRequest::setPeerVerifyName(const QString &peerName) d->peerVerifyName = peerName; } +/*! + \since 5.14 + + Returns the current parameters that QNetworkAccessManager is + using for this request and its underlying HTTP/2 connection. + This is either a configuration previously set by an application + or a default configuration. + + The default values that QNetworkAccessManager is using are: + + \list + \li Window size for connection-level flowcontrol is 2147483647 octets + \li Window size for stream-level flowcontrol is 21474836 octets + \li Max frame size is 16384 + \endlist + + By default, server push is disabled, Huffman compression and + string indexing are enabled. + + \sa setHttp2Configuration +*/ +QHttp2Configuration QNetworkRequest::http2Configuration() const +{ + return d->h2Configuration; +} + +/*! + \since 5.14 + + Sets request's HTTP/2 parameters from \a configuration. + + \note The configuration must be set prior to making a request. + \note HTTP/2 multiplexes several streams in a single HTTP/2 + connection. This implies that QNetworkAccessManager will use + the configuration found in the first request from a series + of requests sent to the same host. + + \sa http2Configuration, QNetworkAccessManager, QHttp2Configuration +*/ +void QNetworkRequest::setHttp2Configuration(const QHttp2Configuration &configuration) +{ + d->h2Configuration = configuration; +} + static QByteArray headerName(QNetworkRequest::KnownHeaders header) { switch (header) { diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h index 8ad4ab41c0..463dabef83 100644 --- a/src/network/access/qnetworkrequest.h +++ b/src/network/access/qnetworkrequest.h @@ -49,6 +49,7 @@ QT_BEGIN_NAMESPACE class QSslConfiguration; +class QHttp2Configuration; class QNetworkRequestPrivate; class Q_NETWORK_EXPORT QNetworkRequest @@ -175,6 +176,9 @@ public: QString peerVerifyName() const; void setPeerVerifyName(const QString &peerName); + + QHttp2Configuration http2Configuration() const; + void setHttp2Configuration(const QHttp2Configuration &configuration); private: QSharedDataPointer d; friend class QNetworkRequestPrivate; diff --git a/tests/auto/network/access/http2/http2srv.cpp b/tests/auto/network/access/http2/http2srv.cpp index 5a99d4e50c..1ddb6aa77d 100644 --- a/tests/auto/network/access/http2/http2srv.cpp +++ b/tests/auto/network/access/http2/http2srv.cpp @@ -76,7 +76,7 @@ void fill_push_header(const HttpHeader &originalRequest, HttpHeader &promisedReq } -Http2Server::Http2Server(H2Type type, const Http2::RawSettings &ss, const Http2::RawSettings &cs) +Http2Server::Http2Server(H2Type type, const RawSettings &ss, const RawSettings &cs) : connectionType(type), serverSettings(ss), expectedClientSettings(cs) @@ -218,7 +218,7 @@ void Http2Server::sendDATA(quint32 streamID, quint32 windowSize) quint32 bytesToSend = std::min(windowSize, responseBody.size() - offset); quint32 bytesSent = 0; - const quint32 frameSizeLimit(clientSetting(Settings::MAX_FRAME_SIZE_ID, Http2::maxFrameSize)); + const quint32 frameSizeLimit(clientSetting(Settings::MAX_FRAME_SIZE_ID, Http2::maxPayloadSize)); const uchar *src = reinterpret_cast(responseBody.constData() + offset); const bool last = offset + bytesToSend == quint32(responseBody.size()); @@ -767,7 +767,7 @@ void Http2Server::sendResponse(quint32 streamID, bool emptyBody) Q_ASSERT(activeRequests.find(streamID) != activeRequests.end()); const quint32 maxFrameSize(clientSetting(Settings::MAX_FRAME_SIZE_ID, - Http2::maxFrameSize)); + Http2::maxPayloadSize)); if (pushPromiseEnabled) { // A real server supporting PUSH_PROMISE will probably first send diff --git a/tests/auto/network/access/http2/http2srv.h b/tests/auto/network/access/http2/http2srv.h index 4ef4b25101..9cb846b0b3 100644 --- a/tests/auto/network/access/http2/http2srv.h +++ b/tests/auto/network/access/http2/http2srv.h @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -69,13 +70,15 @@ enum class H2Type { h2cDirect, // Clear text direct }; +using RawSettings = QMap; + class Http2Server : public QTcpServer { Q_OBJECT public: - Http2Server(H2Type type, const Http2::RawSettings &serverSettings, - const Http2::RawSettings &clientSettings); + Http2Server(H2Type type, const RawSettings &serverSettings, + const RawSettings &clientSettings); ~Http2Server(); @@ -147,8 +150,8 @@ private: bool settingsSent = false; bool waitingClientAck = false; - Http2::RawSettings serverSettings; - Http2::RawSettings expectedClientSettings; + RawSettings serverSettings; + RawSettings expectedClientSettings; bool connectionError = false; diff --git a/tests/auto/network/access/http2/tst_http2.cpp b/tests/auto/network/access/http2/tst_http2.cpp index 945ea1b448..6a0dc6db02 100644 --- a/tests/auto/network/access/http2/tst_http2.cpp +++ b/tests/auto/network/access/http2/tst_http2.cpp @@ -32,8 +32,10 @@ #include #include +#include #include #include + #include #include #include @@ -66,6 +68,24 @@ Q_DECLARE_METATYPE(QNetworkRequest::Attribute) QT_BEGIN_NAMESPACE +QHttp2Configuration qt_defaultH2Configuration() +{ + QHttp2Configuration config; + config.setStreamReceiveWindowSize(Http2::qtDefaultStreamReceiveWindowSize); + config.setSessionReceiveWindowSize(Http2::maxSessionReceiveWindowSize); + config.setServerPushEnabled(false); + return config; +} + +RawSettings qt_H2ConfigurationToSettings(const QHttp2Configuration &config = qt_defaultH2Configuration()) +{ + RawSettings settings; + settings[Http2::Settings::ENABLE_PUSH_ID] = config.serverPushEnabled(); + settings[Http2::Settings::INITIAL_WINDOW_SIZE_ID] = config.streamReceiveWindowSize(); + return settings; +} + + class tst_Http2 : public QObject { Q_OBJECT @@ -110,12 +130,13 @@ private: // small payload. void runEventLoop(int ms = 5000); void stopEventLoop(); - Http2Server *newServer(const Http2::RawSettings &serverSettings, H2Type connectionType, - const Http2::ProtocolParameters &clientSettings = {}); + Http2Server *newServer(const RawSettings &serverSettings, H2Type connectionType, + const RawSettings &clientSettings = qt_H2ConfigurationToSettings()); // Send a get or post request, depending on a payload (empty or not). void sendRequest(int streamNumber, QNetworkRequest::Priority priority = QNetworkRequest::NormalPriority, - const QByteArray &payload = QByteArray()); + const QByteArray &payload = QByteArray(), + const QHttp2Configuration &clientConfiguration = qt_defaultH2Configuration()); QUrl requestUrl(H2Type connnectionType) const; quint16 serverPort = 0; @@ -131,14 +152,14 @@ private: bool prefaceOK = false; bool serverGotSettingsACK = false; - static const Http2::RawSettings defaultServerSettings; + static const RawSettings defaultServerSettings; }; #define STOP_ON_FAILURE \ if (QTest::currentTestFailed()) \ return; -const Http2::RawSettings tst_Http2::defaultServerSettings{{Http2::Settings::MAX_CONCURRENT_STREAMS_ID, 100}}; +const RawSettings tst_Http2::defaultServerSettings{{Http2::Settings::MAX_CONCURRENT_STREAMS_ID, 100}}; namespace { @@ -308,18 +329,15 @@ void tst_Http2::flowControlClientSide() nRequests = 10; windowUpdates = 0; - Http2::ProtocolParameters params; + QHttp2Configuration params; // A small window size for a session, and even a smaller one per stream - // this will result in WINDOW_UPDATE frames both on connection stream and // per stream. - params.maxSessionReceiveWindowSize = Http2::defaultSessionWindowSize * 5; - params.settingsFrameData[Settings::INITIAL_WINDOW_SIZE_ID] = Http2::defaultSessionWindowSize; - // Inform our manager about non-default settings: - manager->setProperty(Http2::http2ParametersPropertyName, QVariant::fromValue(params)); - - const Http2::RawSettings serverSettings = {{Settings::MAX_CONCURRENT_STREAMS_ID, quint32(3)}}; - ServerPtr srv(newServer(serverSettings, defaultConnectionType(), params)); + params.setSessionReceiveWindowSize(Http2::defaultSessionWindowSize * 5); + params.setStreamReceiveWindowSize(Http2::defaultSessionWindowSize); + const RawSettings serverSettings = {{Settings::MAX_CONCURRENT_STREAMS_ID, quint32(3)}}; + ServerPtr srv(newServer(serverSettings, defaultConnectionType(), qt_H2ConfigurationToSettings(params))); const QByteArray respond(int(Http2::defaultSessionWindowSize * 10), 'x'); srv->setResponseBody(respond); @@ -330,7 +348,7 @@ void tst_Http2::flowControlClientSide() QVERIFY(serverPort != 0); for (int i = 0; i < nRequests; ++i) - sendRequest(i); + sendRequest(i, QNetworkRequest::NormalPriority, {}, params); runEventLoop(120000); STOP_ON_FAILURE @@ -359,7 +377,7 @@ void tst_Http2::flowControlServerSide() serverPort = 0; nRequests = 10; - const Http2::RawSettings serverSettings = {{Settings::MAX_CONCURRENT_STREAMS_ID, 7}}; + const RawSettings serverSettings = {{Settings::MAX_CONCURRENT_STREAMS_ID, 7}}; ServerPtr srv(newServer(serverSettings, defaultConnectionType())); @@ -392,12 +410,11 @@ void tst_Http2::pushPromise() serverPort = 0; nRequests = 1; - Http2::ProtocolParameters params; + QHttp2Configuration params; // Defaults are good, except ENABLE_PUSH: - params.settingsFrameData[Settings::ENABLE_PUSH_ID] = 1; - manager->setProperty(Http2::http2ParametersPropertyName, QVariant::fromValue(params)); + params.setServerPushEnabled(true); - ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType(), params)); + ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType(), qt_H2ConfigurationToSettings(params))); srv->enablePushPromise(true, QByteArray("/script.js")); QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection); @@ -410,6 +427,7 @@ void tst_Http2::pushPromise() QNetworkRequest request(url); request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, QVariant(true)); + request.setHttp2Configuration(params); auto reply = manager->get(request); connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished); @@ -689,7 +707,6 @@ void tst_Http2::clearHTTP2State() windowUpdates = 0; prefaceOK = false; serverGotSettingsACK = false; - manager->setProperty(Http2::http2ParametersPropertyName, QVariant()); } void tst_Http2::runEventLoop(int ms) @@ -702,12 +719,11 @@ void tst_Http2::stopEventLoop() eventLoop.exitLoop(); } -Http2Server *tst_Http2::newServer(const Http2::RawSettings &serverSettings, H2Type connectionType, - const Http2::ProtocolParameters &clientSettings) +Http2Server *tst_Http2::newServer(const RawSettings &serverSettings, H2Type connectionType, + const RawSettings &clientSettings) { using namespace Http2; - auto srv = new Http2Server(connectionType, serverSettings, - clientSettings.settingsFrameData); + auto srv = new Http2Server(connectionType, serverSettings, clientSettings); using Srv = Http2Server; using Cl = tst_Http2; @@ -729,7 +745,8 @@ Http2Server *tst_Http2::newServer(const Http2::RawSettings &serverSettings, H2Ty void tst_Http2::sendRequest(int streamNumber, QNetworkRequest::Priority priority, - const QByteArray &payload) + const QByteArray &payload, + const QHttp2Configuration &h2Config) { auto url = requestUrl(defaultConnectionType()); url.setPath(QString("/stream%1.html").arg(streamNumber)); @@ -739,6 +756,7 @@ void tst_Http2::sendRequest(int streamNumber, request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, QVariant(true)); request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain")); request.setPriority(priority); + request.setHttp2Configuration(h2Config); QNetworkReply *reply = nullptr; if (payload.size()) -- cgit v1.2.3 From 5248e895adc51fa70a59d2f49db6032f320bace9 Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Tue, 20 Aug 2019 12:27:30 +0900 Subject: Fix build without features.mimetype Change-Id: I9d3c20845b9ddecbafd6dfd756c5d17ae0c6b5fc Reviewed-by: Volker Hilsheimer --- src/plugins/printsupport/cups/qppdprintdevice.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/printsupport/cups/qppdprintdevice.cpp b/src/plugins/printsupport/cups/qppdprintdevice.cpp index ea6336c4d1..90411f2a2c 100644 --- a/src/plugins/printsupport/cups/qppdprintdevice.cpp +++ b/src/plugins/printsupport/cups/qppdprintdevice.cpp @@ -41,7 +41,9 @@ #include "qcupsprintersupport_p.h" +#if QT_CONFIG(mimetype) #include +#endif #include #include "private/qcups_p.h" // Only needed for PDPK_* -- cgit v1.2.3 From aa6e0e3e30ec7f330e2fbc02fc9fbe55ef0b6432 Mon Sep 17 00:00:00 2001 From: Sona Kurazyan Date: Tue, 20 Aug 2019 12:44:41 +0200 Subject: Remove the usage of deprecated APIs from QSysInfo Replaced: QSysInfo::macVersion() -> QOperatingSystemVersion::current() Q_MV_OSX(10, 13) -> QOperatingSystemVersion::MacOSHighSierra Task-number: QTBUG-76491 Change-Id: Iae4f9c319ff16314fb04bbefaa48935a0f618007 Reviewed-by: Volker Hilsheimer --- tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp b/tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp index da75e64d1e..243cb6483e 100644 --- a/tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp +++ b/tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp @@ -417,7 +417,7 @@ void tst_QWizard::setPixmap() QVERIFY(wizard.pixmap(QWizard::BannerPixmap).isNull()); QVERIFY(wizard.pixmap(QWizard::LogoPixmap).isNull()); QVERIFY(wizard.pixmap(QWizard::WatermarkPixmap).isNull()); - if (QSysInfo::macVersion() <= Q_MV_OSX(10, 13)) + if (QOperatingSystemVersion::current() <= QOperatingSystemVersion::MacOSHighSierra) QVERIFY(!wizard.pixmap(QWizard::BackgroundPixmap).isNull()); else QVERIFY(wizard.pixmap(QWizard::BackgroundPixmap).isNull()); @@ -425,7 +425,7 @@ void tst_QWizard::setPixmap() QVERIFY(page->pixmap(QWizard::BannerPixmap).isNull()); QVERIFY(page->pixmap(QWizard::LogoPixmap).isNull()); QVERIFY(page->pixmap(QWizard::WatermarkPixmap).isNull()); - if (QSysInfo::macVersion() <= Q_MV_OSX(10, 13)) + if (QOperatingSystemVersion::current() <= QOperatingSystemVersion::MacOSHighSierra) QVERIFY(!wizard.pixmap(QWizard::BackgroundPixmap).isNull()); else QVERIFY(page->pixmap(QWizard::BackgroundPixmap).isNull()); -- cgit v1.2.3 From 9e86fdb6e8004a0eba7d5f4b9a7b1f52275fd207 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 19 Aug 2019 12:53:10 +0200 Subject: Support writing color space profile in JPEG That way the image formats with color space supports all have both read and write support. Change-Id: Ib52ebd56192c4a8a0897a6afc7c4a26020319270 Reviewed-by: Eirik Aavitsland --- src/plugins/imageformats/jpeg/qjpeghandler.cpp | 29 ++++++++++++++++++++-- .../gui/image/qimagereader/tst_qimagereader.cpp | 7 ++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp index 0fb21df1d3..1f1675e490 100644 --- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp +++ b/src/plugins/imageformats/jpeg/qjpeghandler.cpp @@ -492,6 +492,8 @@ inline my_jpeg_destination_mgr::my_jpeg_destination_mgr(QIODevice *device) free_in_buffer = max_buf; } +static constexpr int maxMarkerSize = 65533; + static inline void set_text(const QImage &image, j_compress_ptr cinfo, const QString &description) { const QMap text = qt_getImageText(image, description); @@ -500,12 +502,33 @@ static inline void set_text(const QImage &image, j_compress_ptr cinfo, const QSt if (!comment.isEmpty()) comment += ": "; comment += it.value().toUtf8(); - if (comment.length() > 65530) - comment.truncate(65530); + if (comment.length() > maxMarkerSize) + comment.truncate(maxMarkerSize); jpeg_write_marker(cinfo, JPEG_COM, (const JOCTET *)comment.constData(), comment.size()); } } +static inline void write_icc_profile(const QImage &image, j_compress_ptr cinfo) +{ + const QByteArray iccProfile = image.colorSpace().iccProfile(); + if (iccProfile.isEmpty()) + return; + + const QByteArray iccSignature("ICC_PROFILE", 12); + constexpr int maxIccMarkerSize = maxMarkerSize - (12 + 2); + int index = 0; + const int markers = (iccProfile.size() + (maxIccMarkerSize - 1)) / maxIccMarkerSize; + Q_ASSERT(markers < 256); + for (int marker = 1; marker <= markers; ++marker) { + const int len = std::min(iccProfile.size() - index, maxIccMarkerSize); + const QByteArray block = iccSignature + + QByteArray(1, char(marker)) + QByteArray(1, char(markers)) + + iccProfile.mid(index, len); + jpeg_write_marker(cinfo, JPEG_APP0 + 2, reinterpret_cast(block.constData()), block.size()); + index += len; + } +} + static bool write_jpeg_image(const QImage &image, QIODevice *device, volatile int sourceQuality, const QString &description, bool optimize, bool progressive) { bool success = false; @@ -586,6 +609,8 @@ static bool write_jpeg_image(const QImage &image, QIODevice *device, volatile in jpeg_start_compress(&cinfo, TRUE); set_text(image, &cinfo, description); + if (cinfo.in_color_space == JCS_RGB) + write_icc_profile(image, &cinfo); row_pointer[0] = new uchar[cinfo.image_width*cinfo.input_components]; int w = cinfo.image_width; diff --git a/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp index 866a41c3d1..eeabfd0413 100644 --- a/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp +++ b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp @@ -1914,6 +1914,13 @@ void tst_QImageReader::saveColorSpace() QCOMPARE(stored, orig); QCOMPARE(stored.colorSpace(), orig.colorSpace()); + + buf.open(QIODevice::WriteOnly); + QVERIFY(orig.save(&buf, "jpeg")); + buf.close(); + stored = QImage::fromData(buf.buffer(), "jpeg"); + + QCOMPARE(stored.colorSpace(), orig.colorSpace()); } void tst_QImageReader::readText_data() -- cgit v1.2.3 From f556505f63a4255b681ba8a32e1f29ccb79725ce Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Fri, 24 May 2019 22:06:09 +0200 Subject: QWidget: replace manual memory management with unique_ptr [6/N]: extra Had to port a lot of caching temporaries, too. Decided to leave them as crefs to unique_ptr to catch any mischief users may be doing with the raw pointer instead (like deleting it). Also fixed a use of 0 as nullptr (by standardizing on pointer-to-bool conversion, as is done everywhere else in qwidget.cpp), and made one impregnable if condition readable. Change-Id: Ifdc240bf352c52de0bc3c186fa7a5f4cb2882dd0 Reviewed-by: Volker Hilsheimer --- src/widgets/graphicsview/qgraphicsproxywidget.cpp | 12 ++++----- src/widgets/kernel/qapplication.cpp | 4 +-- src/widgets/kernel/qshortcut.cpp | 2 +- src/widgets/kernel/qwidget.cpp | 30 +++++++++++------------ src/widgets/kernel/qwidget_p.h | 4 +-- 5 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/widgets/graphicsview/qgraphicsproxywidget.cpp b/src/widgets/graphicsview/qgraphicsproxywidget.cpp index 2b6712075f..7413a26261 100644 --- a/src/widgets/graphicsview/qgraphicsproxywidget.cpp +++ b/src/widgets/graphicsview/qgraphicsproxywidget.cpp @@ -404,7 +404,7 @@ void QGraphicsProxyWidgetPrivate::_q_removeWidgetSlot() { Q_Q(QGraphicsProxyWidget); if (!widget.isNull()) { - if (QWExtra *extra = widget->d_func()->extra) + if (const auto &extra = widget->d_func()->extra) extra->proxyWidget = 0; } widget = 0; @@ -477,8 +477,8 @@ void QGraphicsProxyWidgetPrivate::updateProxyInputMethodAcceptanceFromWidget() */ void QGraphicsProxyWidgetPrivate::embedSubWindow(QWidget *subWin) { - QWExtra *extra; - if (!((extra = subWin->d_func()->extra) && extra->proxyWidget)) { + const auto &extra = subWin->d_func()->extra; + if (!extra || !extra->proxyWidget) { QGraphicsProxyWidget *subProxy = new QGraphicsProxyWidget(q_func(), subWin->windowFlags()); subProxy->d_func()->setWidget_helper(subWin, false); } @@ -631,7 +631,7 @@ void QGraphicsProxyWidgetPrivate::setWidget_helper(QWidget *newWidget, bool auto if (!newWidget) return; if (!newWidget->isWindow()) { - QWExtra *extra = newWidget->parentWidget()->d_func()->extra; + const auto &extra = newWidget->parentWidget()->d_func()->extra; if (!extra || !extra->proxyWidget) { qWarning("QGraphicsProxyWidget::setWidget: cannot embed widget %p " "which is not a toplevel widget, and is not a child of an embedded widget", newWidget); @@ -641,10 +641,10 @@ void QGraphicsProxyWidgetPrivate::setWidget_helper(QWidget *newWidget, bool auto // Register this proxy within the widget's private. // ### This is a bit backdoorish - QWExtra *extra = newWidget->d_func()->extra; + QWExtra *extra = newWidget->d_func()->extra.get(); if (!extra) { newWidget->d_func()->createExtra(); - extra = newWidget->d_func()->extra; + extra = newWidget->d_func()->extra.get(); } QGraphicsProxyWidget **proxyWidget = &extra->proxyWidget; if (*proxyWidget) { diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 94b14ecb4f..629c696544 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -3388,7 +3388,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) #if QT_CONFIG(graphicsview) // QGraphicsProxyWidget handles its own propagation, // and we must not change QDragManagers currentTarget. - QWExtra *extra = w->window()->d_func()->extra; + const auto &extra = w->window()->d_func()->extra; if (extra && extra->proxyWidget) { res = d->notify_helper(w, dragEvent); break; @@ -3416,7 +3416,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) #if QT_CONFIG(graphicsview) // QGraphicsProxyWidget handles its own propagation, // and we must not change QDragManagers currentTarget. - QWExtra *extra = w->window()->d_func()->extra; + const auto &extra = w->window()->d_func()->extra; bool isProxyWidget = extra && extra->proxyWidget; if (!isProxyWidget) #endif diff --git a/src/widgets/kernel/qshortcut.cpp b/src/widgets/kernel/qshortcut.cpp index a4ebcdfc84..39b08dbc1e 100644 --- a/src/widgets/kernel/qshortcut.cpp +++ b/src/widgets/kernel/qshortcut.cpp @@ -178,7 +178,7 @@ static bool correctWidgetContext(Qt::ShortcutContext context, QWidget *w, QWidge // Below is Qt::WindowShortcut context QWidget *tlw = w->window(); #if QT_CONFIG(graphicsview) - if (auto topData = static_cast(QObjectPrivate::get(tlw))->extra) { + if (auto topData = static_cast(QObjectPrivate::get(tlw))->extra.get()) { if (topData->proxyWidget) { bool res = correctGraphicsWidgetContext(context, topData->proxyWidget, active_window); return res; diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 066dfaa183..2edbe05e32 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -148,7 +148,6 @@ extern QDesktopWidget *qt_desktopWidget; // qapplication.cpp QWidgetPrivate::QWidgetPrivate(int version) : QObjectPrivate(version) - , extra(0) , focus_next(0) , focus_prev(0) , focus_child(0) @@ -1553,7 +1552,7 @@ QWidget::~QWidget() while (w->d_func()->extra && w->d_func()->extra->focus_proxy) w = w->d_func()->extra->focus_proxy; QWidget *window = w->window(); - QWExtra *e = window ? window->d_func()->extra : 0; + QWExtra *e = window ? window->d_func()->extra.get() : nullptr ; if (!e || !e->proxyWidget || (w->parentWidget() && w->parentWidget()->d_func()->focus_child == this)) #endif clearFocus(); @@ -1732,7 +1731,7 @@ void QWidgetPrivate::createTLExtra() void QWidgetPrivate::createExtra() { if (!extra) { // if not exists - extra = new QWExtra; + extra = qt_make_unique(); extra->glContext = 0; #if QT_CONFIG(graphicsview) extra->proxyWidget = 0; @@ -1780,9 +1779,8 @@ void QWidgetPrivate::deleteExtra() deleteTLSysExtra(); // extra->topextra->backingStore destroyed in QWidgetPrivate::deleteTLSysExtra() } - delete extra; // extra->xic destroyed in QWidget::destroy() - extra = 0; + extra.reset(); } } @@ -1853,7 +1851,7 @@ QRegion QWidgetPrivate::overlappedRegion(const QRect &rect, bool breakAfterFirst const QRect siblingRect = sibling->d_func()->effectiveRectFor(sibling->data->crect); if (qRectIntersects(siblingRect, r)) { - const QWExtra *siblingExtra = sibling->d_func()->extra; + const auto &siblingExtra = sibling->d_func()->extra; if (siblingExtra && siblingExtra->hasMask && !sibling->d_func()->graphicsEffect && !siblingExtra->mask.translated(sibling->data->crect.topLeft()).intersects(r)) { continue; @@ -3858,7 +3856,7 @@ QSize QWidget::sizeIncrement() const QSize QWidget::baseSize() const { Q_D(const QWidget); - return (d->extra != 0 && d->extra->topextra != 0) + return (d->extra && d->extra->topextra) ? QSize(d->extra->topextra->basew, d->extra->topextra->baseh) : QSize(0, 0); } @@ -5858,7 +5856,7 @@ QPixmap QWidgetEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint * QGraphicsProxyWidget *QWidgetPrivate::nearestGraphicsProxyWidget(const QWidget *origin) { if (origin) { - QWExtra *extra = origin->d_func()->extra; + const auto &extra = origin->d_func()->extra; if (extra && extra->proxyWidget) return extra->proxyWidget; return nearestGraphicsProxyWidget(origin->parentWidget()); @@ -6404,7 +6402,7 @@ bool QWidget::hasFocus() const w = w->d_func()->extra->focus_proxy; #if QT_CONFIG(graphicsview) if (QWidget *window = w->window()) { - QWExtra *e = window->d_func()->extra; + const auto &e = window->d_func()->extra; if (e && e->proxyWidget && e->proxyWidget->hasFocus() && window->focusWidget() == w) return true; } @@ -6465,7 +6463,7 @@ void QWidget::setFocus(Qt::FocusReason reason) #if QT_CONFIG(graphicsview) QWidget *previousProxyFocus = 0; - if (QWExtra *topData = window()->d_func()->extra) { + if (const auto &topData = window()->d_func()->extra) { if (topData->proxyWidget && topData->proxyWidget->hasFocus()) { previousProxyFocus = topData->proxyWidget->widget()->focusWidget(); if (previousProxyFocus && previousProxyFocus->focusProxy()) @@ -6478,7 +6476,7 @@ void QWidget::setFocus(Qt::FocusReason reason) #if QT_CONFIG(graphicsview) // Update proxy state - if (QWExtra *topData = window()->d_func()->extra) { + if (const auto &topData = window()->d_func()->extra) { if (topData->proxyWidget && !topData->proxyWidget->hasFocus()) { f->d_func()->updateFocusChild(); topData->proxyWidget->d_func()->focusFromWidgetToProxy = 1; @@ -6519,7 +6517,7 @@ void QWidget::setFocus(Qt::FocusReason reason) } #endif #if QT_CONFIG(graphicsview) - if (QWExtra *topData = window()->d_func()->extra) { + if (const auto &topData = window()->d_func()->extra) { if (topData->proxyWidget) { if (previousProxyFocus && previousProxyFocus != f) { // Send event to self @@ -6532,7 +6530,7 @@ void QWidget::setFocus(Qt::FocusReason reason) if (!isHidden()) { #if QT_CONFIG(graphicsview) // Update proxy state - if (QWExtra *topData = window()->d_func()->extra) + if (const auto &topData = window()->d_func()->extra) if (topData->proxyWidget && topData->proxyWidget->hasFocus()) topData->proxyWidget->d_func()->updateProxyInputMethodAcceptanceFromWidget(); #endif @@ -6669,7 +6667,7 @@ void QWidget::clearFocus() } #if QT_CONFIG(graphicsview) - QWExtra *topData = d_func()->extra; + const auto &topData = d_func()->extra; if (topData && topData->proxyWidget) topData->proxyWidget->clearFocus(); #endif @@ -6835,7 +6833,7 @@ bool QWidget::isActiveWindow() const return true; #if QT_CONFIG(graphicsview) - if (QWExtra *tlwExtra = tlw->d_func()->extra) { + if (const auto &tlwExtra = tlw->d_func()->extra) { if (isVisible() && tlwExtra->proxyWidget) return tlwExtra->proxyWidget->isActiveWindow(); } @@ -10325,7 +10323,7 @@ void QWidget::setSizePolicy(QSizePolicy policy) d->size_policy = policy; #if QT_CONFIG(graphicsview) - if (QWExtra *extra = d->extra) { + if (const auto &extra = d->extra) { if (extra->proxyWidget) extra->proxyWidget->setSizePolicy(policy); } diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index b4a9d283db..687e8bef09 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -669,7 +669,7 @@ public: // Variables. // Regular pointers (keep them together to avoid gaps on 64 bit architectures). - QWExtra *extra; + std::unique_ptr extra; QWidget *focus_next; QWidget *focus_prev; QWidget *focus_child; @@ -945,7 +945,7 @@ public: inline QWExtra *QWidgetPrivate::extraData() const { - return extra; + return extra.get(); } inline QTLWExtra *QWidgetPrivate::topData() const -- cgit v1.2.3 From 9f082b4e03a52ed651e636f765eb076d3e56a2f4 Mon Sep 17 00:00:00 2001 From: Sona Kurazyan Date: Tue, 20 Aug 2019 14:59:16 +0200 Subject: Clean up the docs of qevent.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Build the docs for deprecated APIs conditionally, based on deprecation version. - Remove the docs of methods deprecated since 5.0.0, these methods are not compiled anymore. Change-Id: I2c1b038ce125ca737944f4fc4a28e2f6852eaded Reviewed-by: Tor Arne Vestbø --- src/gui/kernel/qevent.cpp | 52 ++--------------------------------------------- 1 file changed, 2 insertions(+), 50 deletions(-) diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index ec52791010..d79066adf2 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -534,13 +534,6 @@ Qt::MouseEventFlags QMouseEvent::flags() const \sa button(), Qt::MouseButton */ -/*! - \fn QPointF QMouseEvent::posF() const - \obsolete - - Use localPos() instead. -*/ - /*! \class QHoverEvent \ingroup events @@ -1101,16 +1094,6 @@ QKeyEvent::~QKeyEvent() { } -/*! - \fn QKeyEvent *QKeyEvent::createExtendedKeyEvent(Type type, int key, Qt::KeyboardModifiers modifiers, quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, const QString& text, bool autorep, ushort count) - \internal -*/ - -/*! - \fn bool QKeyEvent::hasExtendedInfo() const - \internal -*/ - /*! \fn quint32 QKeyEvent::nativeScanCode() const \since 4.2 @@ -2539,7 +2522,7 @@ Qt::MouseButtons QTabletEvent::buttons() const globalPos() can differ significantly from the current position QCursor::pos(). - \sa globalX(), globalY(), hiResGlobalPos() + \sa globalX(), globalY() */ /*! @@ -2583,15 +2566,6 @@ Qt::MouseButtons QTabletEvent::buttons() const \sa pointerType() */ -/*! - \fn const QPointF &QTabletEvent::hiResGlobalPos() const - - The high precision coordinates delivered from the tablet expressed. - Sub pixeling information is in the fractional part of the QPointF. - - \sa globalPos(), hiResGlobalX(), hiResGlobalY() -*/ - /*! \fn qreal &QTabletEvent::hiResGlobalX() const @@ -2674,10 +2648,10 @@ Qt::MouseButtons QTabletEvent::buttons() const \sa Qt::NativeGestureType, QGestureEvent */ +#if QT_DEPRECATED_SINCE(5, 10) /*! \deprecated The QTouchDevice parameter is now required */ -#if QT_DEPRECATED_SINCE(5, 10) QNativeGestureEvent::QNativeGestureEvent(Qt::NativeGestureType type, const QPointF &localPos, const QPointF &windowPos, const QPointF &screenPos, qreal realValue, ulong sequenceId, quint64 intValue) : QInputEvent(QEvent::NativeGesture), mGestureType(type), @@ -4290,18 +4264,6 @@ QWindowStateChangeEvent::~QWindowStateChangeEvent() QGraphicsItem::acceptTouchEvents() */ -/*! \enum QTouchEvent::DeviceType - \obsolete - - This enum represents the type of device that generated a QTouchEvent. - - This enum has been deprecated. Use QTouchDevice::DeviceType instead. - \omitvalue TouchPad - \omitvalue TouchScreen - - \sa QTouchDevice::DeviceType, QTouchDevice::type(), QTouchEvent::device() -*/ - /*! Constructs a QTouchEvent with the given \a eventType, \a device, and \a touchPoints. The \a touchPointStates and \a modifiers @@ -4341,16 +4303,6 @@ QTouchEvent::~QTouchEvent() This is typically a QWidget or a QQuickItem. May be 0 when no specific target is available. */ -/*! \fn QTouchEvent::DeviceType QTouchEvent::deviceType() const - \obsolete - - Returns the touch device Type, which is of type \l {QTouchEvent::DeviceType} {DeviceType}. - - This function has been deprecated. Use QTouchDevice::type() instead. - - \sa QTouchDevice::type(), QTouchEvent::device() -*/ - /*! \fn QTouchEvent::TouchPoint::TouchPoint(TouchPoint &&other) Move-constructs a TouchPoint instance, making it point to the same -- cgit v1.2.3 From d46415c0af5c84b5924694a090a0cd70fdb18158 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Mon, 12 Aug 2019 23:32:44 +0200 Subject: wasm: Add saveFileContent() Saves a file by file download, where the user can choose the file name and location using a file dialog. Change-Id: I4d2ecc76fc33bb65fdf3d7ca3fcd9566c62547dd Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/platform/wasm/qwasmlocalfileaccess.cpp | 37 ++++++++++++++++++ src/gui/platform/wasm/qwasmlocalfileaccess_p.h | 2 + src/widgets/dialogs/qfiledialog.cpp | 45 ++++++++++++++++++++++ src/widgets/dialogs/qfiledialog.h | 1 + .../snippets/code/src_gui_dialogs_qfiledialog.cpp | 5 +++ 5 files changed, 90 insertions(+) diff --git a/src/gui/platform/wasm/qwasmlocalfileaccess.cpp b/src/gui/platform/wasm/qwasmlocalfileaccess.cpp index 83f9415c69..85c894a74a 100644 --- a/src/gui/platform/wasm/qwasmlocalfileaccess.cpp +++ b/src/gui/platform/wasm/qwasmlocalfileaccess.cpp @@ -164,6 +164,43 @@ void openFile(const std::string &accept, openFiles(accept, FileSelectMode::SingleFile, fileDialogClosedWithInt, acceptFile, fileDataReady); } +void saveFile(const char *content, size_t size, const std::string &fileNameHint) +{ + // Save a file by creating programatically clicking a download + // link to an object url to a Blob containing the file content. + // File content is copied once, so that the passed in content + // buffer can be released as soon as this function returns - we + // don't know for how long the browser will retain the TypedArray + // view used to create the Blob. + + emscripten::val document = emscripten::val::global("document"); + emscripten::val window = emscripten::val::global("window"); + + emscripten::val fileContentView = emscripten::val(emscripten::typed_memory_view(size, content)); + emscripten::val fileContentCopy = emscripten::val::global("ArrayBuffer").new_(size); + emscripten::val fileContentCopyView = emscripten::val::global("Uint8Array").new_(fileContentCopy); + fileContentCopyView.call("set", fileContentView); + + emscripten::val contentArray = emscripten::val::array(); + contentArray.call("push", fileContentCopyView); + emscripten::val type = emscripten::val::object(); + type.set("type","application/octet-stream"); + emscripten::val contentBlob = emscripten::val::global("Blob").new_(contentArray, type); + + emscripten::val contentUrl = window["URL"].call("createObjectURL", contentBlob); + emscripten::val contentLink = document.call("createElement", std::string("a")); + contentLink.set("href", contentUrl); + contentLink.set("download", fileNameHint); + contentLink.set("style", "display:none"); + + emscripten::val body = document["body"]; + body.call("appendChild", contentLink); + contentLink.call("click"); + body.call("removeChild", contentLink); + + window["URL"].call("revokeObjectURL", contentUrl); +} + } // namespace QWasmLocalFileAccess QT_END_NAMESPACE diff --git a/src/gui/platform/wasm/qwasmlocalfileaccess_p.h b/src/gui/platform/wasm/qwasmlocalfileaccess_p.h index 794db8d9b2..ccd88570c8 100644 --- a/src/gui/platform/wasm/qwasmlocalfileaccess_p.h +++ b/src/gui/platform/wasm/qwasmlocalfileaccess_p.h @@ -71,6 +71,8 @@ void openFile(const std::string &accept, const std::function &acceptFile, const std::function &fileDataReady); +void saveFile(const char *content, size_t size, const std::string &fileNameHint); + } // namespace QWasmLocalFileAccess QT_END_NAMESPACE diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index a89192e76f..a1b9003c1c 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -2447,6 +2447,51 @@ void QFileDialog::getOpenFileContent(const QString &nameFilter, const std::funct #endif } +/*! + This is a convenience static function that saves \a fileContent to a file, using + a file name and location chosen by the user. \a fileNameHint can be provided to + suggest a file name to the user. + + This function is used to save files to the local file system on Qt for WebAssembly, where + the web sandbox places restrictions on how such access may happen. Its implementation will + make the browser display a native file dialog, where the user makes the file selection. + + It can also be used on other platforms, where it will fall back to using QFileDialog. + + The function is asynchronous and returns immediately. + + \snippet code/src_gui_dialogs_qfiledialog.cpp 16 + \since 5.14 +*/ +void QFileDialog::saveFileContent(const QByteArray &fileContent, const QString &fileNameHint) +{ +#ifdef Q_OS_WASM + QWasmLocalFileAccess::saveFile(fileContent.constData(), fileContent.size(), fileNameHint.toStdString()); +#else + QFileDialog *dialog = new QFileDialog(); + dialog->setAcceptMode(QFileDialog::AcceptSave); + dialog->setFileMode(QFileDialog::AnyFile); + dialog->selectFile(fileNameHint); + + auto fileSelected = [=](const QString &fileName) { + if (!fileName.isNull()) { + QFile selectedFile(fileName); + if (selectedFile.open(QIODevice::WriteOnly)) + selectedFile.write(fileContent); + } + }; + + auto dialogClosed = [=](int code) { + Q_UNUSED(code); + delete dialog; + }; + + connect(dialog, &QFileDialog::fileSelected, fileSelected); + connect(dialog, &QFileDialog::finished, dialogClosed); + dialog->show(); +#endif +} + /*! This is a convenience static function that will return a file name selected by the user. The file does not have to exist. diff --git a/src/widgets/dialogs/qfiledialog.h b/src/widgets/dialogs/qfiledialog.h index 354a1f928b..790f52f2e7 100644 --- a/src/widgets/dialogs/qfiledialog.h +++ b/src/widgets/dialogs/qfiledialog.h @@ -284,6 +284,7 @@ public: static void getOpenFileContent(const QString &nameFilter, const std::function &fileContentsReady); + static void saveFileContent(const QByteArray &fileContent, const QString &fileNameHint = QString()); protected: QFileDialog(const QFileDialogArgs &args); diff --git a/src/widgets/doc/snippets/code/src_gui_dialogs_qfiledialog.cpp b/src/widgets/doc/snippets/code/src_gui_dialogs_qfiledialog.cpp index 39aca459db..7ccd827a04 100644 --- a/src/widgets/doc/snippets/code/src_gui_dialogs_qfiledialog.cpp +++ b/src/widgets/doc/snippets/code/src_gui_dialogs_qfiledialog.cpp @@ -155,3 +155,8 @@ auto fileOpenCompleted = [](const QString &fileName, const QByteArray &fileConte } QFileDialog::getOpenFileContent("Images (*.png *.xpm *.jpg)", fileContentReady); //! [15] + +//! [16] +QByteArray imageData; // obtained from e.g. QImage::save() +QFileDialog::saveFile("myimage.png", imageData); +//! [16] -- cgit v1.2.3 From 3b5f9678d721f5d44f154408ad8ad5cf08e34ca0 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Tue, 6 Aug 2019 15:06:15 +0200 Subject: Remove dead QMakeSourceFileInfo caching feature from QMake Since its introduction in commit 65bb1a25419210e6097cad973fb847aa3719c09b (old internal history, 2005) with the commit message "optimizations I've been sitting on here" we're dragging along this dead code. It is time for removal. Change-Id: Ic7902ebb8c402734974ad6651a1371d1e5bf93c5 Reviewed-by: Oliver Wolff --- mkspecs/features/qt_module.prf | 2 +- qmake/generators/makefile.cpp | 14 ---- qmake/generators/makefiledeps.cpp | 164 -------------------------------------- qmake/generators/makefiledeps.h | 9 --- 4 files changed, 1 insertion(+), 188 deletions(-) diff --git a/mkspecs/features/qt_module.prf b/mkspecs/features/qt_module.prf index 169d91c746..828a9621b9 100644 --- a/mkspecs/features/qt_module.prf +++ b/mkspecs/features/qt_module.prf @@ -93,7 +93,7 @@ header_module { DESTDIR = $$MODULE_BASE_OUTDIR/lib DLLDESTDIR = $$MODULE_BASE_OUTDIR/bin -CONFIG += qmake_cache target_qt +CONFIG += target_qt QMAKE_DOCS_TARGETDIR = qt$${MODULE} diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index ec73ccfe54..94e9259c68 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -771,20 +771,6 @@ MakefileGenerator::init() QMakeSourceFileInfo::setDependencyPaths(deplist); debug_msg(1, "Dependency Directories: %s", incDirs.join(QString(" :: ")).toLatin1().constData()); - //cache info - if(project->isActiveConfig("qmake_cache")) { - QString cache_file; - if(!project->isEmpty("QMAKE_INTERNAL_CACHE_FILE")) { - cache_file = QDir::fromNativeSeparators(project->first("QMAKE_INTERNAL_CACHE_FILE").toQString()); - } else { - cache_file = ".qmake.internal.cache"; - if(project->isActiveConfig("build_pass")) - cache_file += ".BUILD." + project->first("BUILD_PASS"); - } - if(cache_file.indexOf('/') == -1) - cache_file.prepend(Option::output_dir + '/'); - QMakeSourceFileInfo::setCacheFile(cache_file); - } //add to dependency engine for(x = 0; x < compilers.count(); ++x) { diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp index 10fcc1493c..d68539814e 100644 --- a/qmake/generators/makefiledeps.cpp +++ b/qmake/generators/makefiledeps.cpp @@ -60,8 +60,6 @@ QT_BEGIN_NAMESPACE inline bool qmake_endOfLine(const char &c) { return (c == '\r' || c == '\n'); } #endif -//#define QMAKE_USE_CACHE - QMakeLocalFileName::QMakeLocalFileName(const QString &name) : is_null(name.isNull()) { if(!name.isEmpty()) { @@ -265,19 +263,10 @@ QMakeSourceFileInfo::QMakeSourceFileInfo(const QString &cf) //buffer spare_buffer = nullptr; spare_buffer_size = 0; - - //cache - cachefile = cf; - if(!cachefile.isEmpty()) - loadCache(cachefile); } QMakeSourceFileInfo::~QMakeSourceFileInfo() { - //cache - if(!cachefile.isEmpty() /*&& files_changed*/) - saveCache(cachefile); - //buffer if(spare_buffer) { free(spare_buffer); @@ -290,12 +279,6 @@ QMakeSourceFileInfo::~QMakeSourceFileInfo() delete includes; } -void QMakeSourceFileInfo::setCacheFile(const QString &cf) -{ - cachefile = cf; - loadCache(cachefile); -} - void QMakeSourceFileInfo::addSourceFiles(const ProStringList &l, uchar seek, QMakeSourceFileInfo::SourceFileType type) { @@ -1054,151 +1037,4 @@ bool QMakeSourceFileInfo::findMocs(SourceFile *file) return true; } - -void QMakeSourceFileInfo::saveCache(const QString &cf) -{ -#ifdef QMAKE_USE_CACHE - if(cf.isEmpty()) - return; - - QFile file(QMakeLocalFileName(cf).local()); - if(file.open(QIODevice::WriteOnly)) { - QTextStream stream(&file); - stream << QMAKE_VERSION_STR << endl << endl; //version - { //cache verification - QMap verify = getCacheVerification(); - stream << verify.count() << endl; - for(QMap::iterator it = verify.begin(); - it != verify.end(); ++it) { - stream << it.key() << endl << it.value().join(';') << endl; - } - stream << endl; - } - if(files->nodes) { - for(int file = 0; file < files->num_nodes; ++file) { - for(SourceFiles::SourceFileNode *node = files->nodes[file]; node; node = node->next) { - stream << node->file->file.local() << endl; //source - stream << node->file->type << endl; //type - - //depends - stream << ";"; - if(node->file->deps) { - for(int depend = 0; depend < node->file->deps->used_nodes; ++depend) { - if(depend) - stream << ";"; - stream << node->file->deps->children[depend]->file.local(); - } - } - stream << endl; - - stream << node->file->mocable << endl; //mocable - stream << endl; //just for human readability - } - } - } - stream.flush(); - file.close(); - } -#else - Q_UNUSED(cf); -#endif -} - -void QMakeSourceFileInfo::loadCache(const QString &cf) -{ - if(cf.isEmpty()) - return; - -#ifdef QMAKE_USE_CACHE - QMakeLocalFileName cache_file(cf); - int fd = open(QMakeLocalFileName(cf).local().toLatin1(), O_RDONLY); - if(fd == -1) - return; - QFileInfo cache_fi = findFileInfo(cache_file); - if(!cache_fi.exists() || cache_fi.isDir()) - return; - - QFile file; - if (!file.open(fd, QIODevice::ReadOnly)) - return; - QTextStream stream(&file); - - if (stream.readLine() == QMAKE_VERSION_STR) { //version check - stream.skipWhiteSpace(); - - bool verified = true; - { //cache verification - QMap verify; - int len = stream.readLine().toInt(); - for(int i = 0; i < len; ++i) { - QString var = stream.readLine(); - QString val = stream.readLine(); - verify.insert(var, val.split(';', QString::SkipEmptyParts)); - } - verified = verifyCache(verify); - } - if(verified) { - stream.skipWhiteSpace(); - if(!files) - files = new SourceFiles; - while(!stream.atEnd()) { - QString source = stream.readLine(); - QString type = stream.readLine(); - QString depends = stream.readLine(); - QString mocable = stream.readLine(); - stream.skipWhiteSpace(); - - QMakeLocalFileName fn(source); - QFileInfo fi = findFileInfo(fn); - - SourceFile *file = files->lookupFile(fn); - if(!file) { - file = new SourceFile; - file->file = fn; - files->addFile(file); - file->type = (SourceFileType)type.toInt(); - file->exists = fi.exists(); - } - if(fi.exists() && fi.lastModified() < cache_fi.lastModified()) { - if(!file->dep_checked) { //get depends - if(!file->deps) - file->deps = new SourceDependChildren; - file->dep_checked = true; - QStringList depend_list = depends.split(";", QString::SkipEmptyParts); - for(int depend = 0; depend < depend_list.size(); ++depend) { - QMakeLocalFileName dep_fn(depend_list.at(depend)); - QFileInfo dep_fi(findFileInfo(dep_fn)); - SourceFile *dep = files->lookupFile(dep_fn); - if(!dep) { - dep = new SourceFile; - dep->file = dep_fn; - dep->exists = dep_fi.exists(); - dep->type = QMakeSourceFileInfo::TYPE_UNKNOWN; - files->addFile(dep); - } - dep->included_count++; - file->deps->addChild(dep); - } - } - if(!file->moc_checked) { //get mocs - file->moc_checked = true; - file->mocable = mocable.toInt(); - } - } - } - } - } -#endif -} - -QMap QMakeSourceFileInfo::getCacheVerification() -{ - return QMap(); -} - -bool QMakeSourceFileInfo::verifyCache(const QMap &v) -{ - return v == getCacheVerification(); -} - QT_END_NAMESPACE diff --git a/qmake/generators/makefiledeps.h b/qmake/generators/makefiledeps.h index b91a3e0a0f..66b87bf470 100644 --- a/qmake/generators/makefiledeps.h +++ b/qmake/generators/makefiledeps.h @@ -79,9 +79,6 @@ private: bool findDeps(SourceFile *); void dependTreeWalker(SourceFile *, SourceDependChildren *); - //cache - QString cachefile; - protected: virtual QMakeLocalFileName fixPathForFile(const QMakeLocalFileName &, bool forOpen=false); virtual QMakeLocalFileName findFileForDep(const QMakeLocalFileName &, const QMakeLocalFileName &); @@ -114,12 +111,6 @@ public: bool mocable(const QString &file); - virtual QMap getCacheVerification(); - virtual bool verifyCache(const QMap &); - void setCacheFile(const QString &cachefile); //auto caching - void loadCache(const QString &cf); - void saveCache(const QString &cf); - private: DependencyMode dep_mode; }; -- cgit v1.2.3 From 1d89748772947d38d284c59d59f50fa075d113d6 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Mon, 19 Aug 2019 09:42:21 +0200 Subject: Fix .sln generation for sub-projects with same TARGET Sub-projects in VS solutions must have unique project names. If there are multiple projects with the same TARGET then QMAKE_PROJECT_NAME must be set to different values. The .sln generation code did not use QMAKE_PROJECT_NAME and produced .sln files with equally named sub-projects. Replace the 'orig_target' member of VcsolutionDepend with a 'projectName' member and use it when writing the .sln file and for the misnamed "GUID map" that's supposed to have unique keys. This commit amends 9e750d34 (qt/qt.git). Fixes: QTBUG-77639 Change-Id: I81c64f8bc6baeb6d99e9d5808fb73dfd7aaaeeb8 Reviewed-by: Alexandru Croitor Reviewed-by: Kai Koehne --- qmake/generators/win32/msvc_vcproj.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp index b6f7f20564..06db24df22 100644 --- a/qmake/generators/win32/msvc_vcproj.cpp +++ b/qmake/generators/win32/msvc_vcproj.cpp @@ -209,7 +209,9 @@ bool VcprojGenerator::writeProjectMakefile() struct VcsolutionDepend { QString uuid; - QString vcprojFile, orig_target, target; + QString vcprojFile; + QString projectName; + QString target; Target targetType; QStringList dependencies; }; @@ -433,7 +435,8 @@ ProStringList VcprojGenerator::collectDependencies(QMakeProject *proj, QHashfirst("QMAKE_PROJECT_NAME") + project->first("VCPROJ_EXTENSION"); + const ProString projectName = tmp_vcproj.project->first("QMAKE_PROJECT_NAME"); + const QString vcproj = projectName + project->first("VCPROJ_EXTENSION"); QString vcprojDir = Option::output_dir; // If file doesn't exsist, then maybe the users configuration @@ -445,14 +448,14 @@ ProStringList VcprojGenerator::collectDependencies(QMakeProject *proj, QHashvcprojFile = vcprojDir + Option::dir_sep + vcproj; - newDep->orig_target = tmp_proj.first("QMAKE_ORIG_TARGET").toQString(); + newDep->projectName = projectName.toQString(); newDep->target = tmp_proj.first("MSVCPROJ_TARGET").toQString().section(Option::dir_sep, -1); newDep->targetType = tmp_vcproj.projectTarget; newDep->uuid = tmp_proj.isEmpty("QMAKE_UUID") ? getProjectUUID(Option::fixPathToLocalOS(vcprojDir + QDir::separator() + vcproj)).toString().toUpper(): tmp_proj.first("QMAKE_UUID").toQString(); // We want to store it as the .lib name. if (newDep->target.endsWith(".dll")) newDep->target = newDep->target.left(newDep->target.length()-3) + "lib"; - projGuids.insert(newDep->orig_target, newDep->target); + projGuids.insert(newDep->projectName, newDep->target); if (tmpList.size()) { const ProStringList depends = tmpList; @@ -591,7 +594,7 @@ void VcprojGenerator::writeSubDirs(QTextStream &t) for (QList::Iterator it = solution_cleanup.begin(); it != solution_cleanup.end(); ++it) { // ### quoting rules? t << _slnProjectBeg << _slnMSVCvcprojGUID << _slnProjectMid - << "\"" << (*it)->orig_target << "\", \"" << (*it)->vcprojFile + << "\"" << (*it)->projectName << "\", \"" << (*it)->vcprojFile << "\", \"" << (*it)->uuid << "\""; debug_msg(1, "Project %s has dependencies: %s", (*it)->target.toLatin1().constData(), (*it)->dependencies.join(" ").toLatin1().constData()); -- cgit v1.2.3 From 2cddaf0071d647221ea4936da22bca86cd523799 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 19 Aug 2019 14:46:28 +0200 Subject: Fix tst_bench_qimagereader It couldn't find the test images if not build in sources. Change-Id: Ieeb5a76694a37d05b3e9a4ed0154885040b0812f Reviewed-by: Daniel Smith Reviewed-by: Eirik Aavitsland --- .../benchmarks/gui/image/qimagereader/qimagereader.pro | 2 ++ .../gui/image/qimagereader/tst_qimagereader.cpp | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/tests/benchmarks/gui/image/qimagereader/qimagereader.pro b/tests/benchmarks/gui/image/qimagereader/qimagereader.pro index 29f7f6b16e..3454cf1474 100644 --- a/tests/benchmarks/gui/image/qimagereader/qimagereader.pro +++ b/tests/benchmarks/gui/image/qimagereader/qimagereader.pro @@ -8,3 +8,5 @@ SOURCES += tst_qimagereader.cpp qtConfig(gif): DEFINES += QTEST_HAVE_GIF qtConfig(jpeg): DEFINES += QTEST_HAVE_JPEG + +TESTDATA += images/* diff --git a/tests/benchmarks/gui/image/qimagereader/tst_qimagereader.cpp b/tests/benchmarks/gui/image/qimagereader/tst_qimagereader.cpp index d81d5bb01a..48e838148f 100644 --- a/tests/benchmarks/gui/image/qimagereader/tst_qimagereader.cpp +++ b/tests/benchmarks/gui/image/qimagereader/tst_qimagereader.cpp @@ -51,6 +51,7 @@ public: virtual ~tst_QImageReader(); public slots: + void initTestCase(); void init(); void cleanup(); @@ -69,6 +70,7 @@ private slots: private: QList< QPair > images; // filename, format + QString prefix; }; tst_QImageReader::tst_QImageReader() @@ -102,6 +104,13 @@ tst_QImageReader::~tst_QImageReader() { } +void tst_QImageReader::initTestCase() +{ + prefix = QFINDTESTDATA("images/"); + if (prefix.isEmpty()) + QFAIL("Can't find images directory!"); +} + void tst_QImageReader::init() { } @@ -128,7 +137,7 @@ void tst_QImageReader::readImage() QFETCH(QByteArray, format); QBENCHMARK { - QImageReader io("images/" + fileName, format); + QImageReader io(prefix + fileName, format); QImage image = io.read(); QVERIFY(!image.isNull()); } @@ -159,7 +168,7 @@ void tst_QImageReader::setScaledSize() QFETCH(QByteArray, format); QBENCHMARK { - QImageReader reader("images/" + fileName, format); + QImageReader reader(prefix + fileName, format); reader.setScaledSize(newSize); QImage image = reader.read(); QCOMPARE(image.size(), newSize); @@ -186,7 +195,7 @@ void tst_QImageReader::setClipRect() QFETCH(QByteArray, format); QBENCHMARK { - QImageReader reader("images/" + fileName, format); + QImageReader reader(prefix + fileName, format); reader.setClipRect(newRect); QImage image = reader.read(); QCOMPARE(image.rect(), newRect); @@ -205,7 +214,7 @@ void tst_QImageReader::setScaledClipRect() QFETCH(QByteArray, format); QBENCHMARK { - QImageReader reader("images/" + fileName, format); + QImageReader reader(prefix + fileName, format); reader.setScaledSize(QSize(300, 300)); reader.setScaledClipRect(newRect); QImage image = reader.read(); -- cgit v1.2.3 From 5e74d0e80c7e68784f38c462b037ba48a43222b3 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sat, 10 Aug 2019 10:51:57 -0700 Subject: forkfd: fix compilation in C mode without precompiled headers Missing one "struct" and one #include for struct rusage. Change-Id: Iec9c051acd73484c8d94fffd15b9a1274703afca Reviewed-by: Marc Mutz Reviewed-by: Edward Welbourne --- src/3rdparty/forkfd/forkfd.c | 4 ++-- src/3rdparty/forkfd/forkfd.h | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/3rdparty/forkfd/forkfd.c b/src/3rdparty/forkfd/forkfd.c index 12537b6199..c2105e93cc 100644 --- a/src/3rdparty/forkfd/forkfd.c +++ b/src/3rdparty/forkfd/forkfd.c @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 Intel Corporation. +** Copyright (C) 2019 Intel Corporation. ** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com ** ** Permission is hereby granted, free of charge, to any person obtaining a copy @@ -843,7 +843,7 @@ out: #endif // _POSIX_SPAWN && !FORKFD_NO_SPAWNFD -int forkfd_wait(int ffd, forkfd_info *info, struct rusage *rusage) +int forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage) { struct pipe_payload payload; int ret; diff --git a/src/3rdparty/forkfd/forkfd.h b/src/3rdparty/forkfd/forkfd.h index 958321c299..eb121de593 100644 --- a/src/3rdparty/forkfd/forkfd.h +++ b/src/3rdparty/forkfd/forkfd.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 Intel Corporation. +** Copyright (C) 2019 Intel Corporation. ** ** Permission is hereby granted, free of charge, to any person obtaining a copy ** of this software and associated documentation files (the "Software"), to deal @@ -27,6 +27,7 @@ #include #include +#include #include // to get the POSIX flags #if _POSIX_SPAWN > 0 @@ -48,7 +49,7 @@ struct forkfd_info { }; int forkfd(int flags, pid_t *ppid); -int forkfd_wait(int ffd, forkfd_info *info, struct rusage *rusage); +int forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage); int forkfd_close(int ffd); #if _POSIX_SPAWN > 0 -- cgit v1.2.3 From 8784ab7ba8718c7254a774e3a487950cb77cd5ec Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sat, 10 Aug 2019 08:11:23 -0700 Subject: forkfd: Add C11 and C++11 atomic support For forkfd, this is extremely useful, since users can rely on proper atomic API, not the old GCC API or the internal API that backs the C11 / C++11 implementation itself. This also caught one more mistaken use of seq_cst. Change-Id: Iec9c051acd73484c8d94fffd15b9985fe545e8b5 Reviewed-by: Marc Mutz --- src/3rdparty/forkfd/forkfd.c | 4 +-- src/3rdparty/forkfd/forkfd_atomic.h | 39 ++++++++++++++++++++++ src/3rdparty/forkfd/forkfd_c11.h | 64 +++++++++++++++++++++++++++++++++++++ src/corelib/io/forkfd_qt.cpp | 29 ++--------------- 4 files changed, 106 insertions(+), 30 deletions(-) create mode 100644 src/3rdparty/forkfd/forkfd_atomic.h create mode 100644 src/3rdparty/forkfd/forkfd_c11.h diff --git a/src/3rdparty/forkfd/forkfd.c b/src/3rdparty/forkfd/forkfd.c index c2105e93cc..17a9b23581 100644 --- a/src/3rdparty/forkfd/forkfd.c +++ b/src/3rdparty/forkfd/forkfd.c @@ -93,9 +93,7 @@ # endif #endif -#ifndef FFD_ATOMIC_RELAXED -# include "forkfd_gcc.h" -#endif +#include "forkfd_atomic.h" #define CHILDREN_IN_SMALL_ARRAY 16 #define CHILDREN_IN_BIG_ARRAY 256 diff --git a/src/3rdparty/forkfd/forkfd_atomic.h b/src/3rdparty/forkfd/forkfd_atomic.h new file mode 100644 index 0000000000..394e30d26c --- /dev/null +++ b/src/3rdparty/forkfd/forkfd_atomic.h @@ -0,0 +1,39 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Intel Corporation. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#if !defined(FFD_ATOMIC_H) & !defined(FFD_ATOMIC_RELAXED) +#define FFD_ATOMIC_H + +#if defined(__cplusplus) && __cplusplus >= 201103L +# include "forkfd_c11.h" +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +# include "forkfd_c11.h" +#elif defined(__GNUC__) +# include "forkfd_gcc.h" +#endif + +#endif /* FFD_ATOMIC_h && FFD_ATOMIC_RELAXED */ +#ifndef FFD_ATOMIC_RELAXED +# error "Could not determine atomics for this platform" +#endif diff --git a/src/3rdparty/forkfd/forkfd_c11.h b/src/3rdparty/forkfd/forkfd_c11.h new file mode 100644 index 0000000000..f3dc2b5357 --- /dev/null +++ b/src/3rdparty/forkfd/forkfd_c11.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Intel Corporation. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#ifndef FFD_ATOMIC_C11_H +#define FFD_ATOMIC_C11_H + +/* atomics */ +/* Using the C11 header or C++11's + */ + +#if defined(__cplusplus) +# include +# define ffd_atomic_pointer(type) std::atomic +# define FFD_ATOMIC_RELAXED std::memory_order_relaxed +# define FFD_ATOMIC_ACQUIRE std::memory_order_acquire +# define FFD_ATOMIC_RELEASE std::memory_order_release +// acq_rel & cst not necessary +typedef std::atomic_int ffd_atomic_int; +#else +# include +# define ffd_atomic_pointer(type) _Atomic(type*) +# define FFD_ATOMIC_RELAXED memory_order_relaxed +# define FFD_ATOMIC_ACQUIRE memory_order_acquire +# define FFD_ATOMIC_RELEASE memory_order_release +// acq_rel & cst not necessary + +typedef atomic_int ffd_atomic_int; +#endif + +#define FFD_ATOMIC_INIT(val) ATOMIC_VAR_INIT(val) + +#define ffd_atomic_load(ptr, order) \ + atomic_load_explicit(ptr, order) +#define ffd_atomic_store(ptr, val, order) \ + atomic_store_explicit(ptr, val, order) +#define ffd_atomic_exchange(ptr,val,order) \ + atomic_exchange_explicit(ptr, val, order) +#define ffd_atomic_compare_exchange(ptr, expected, desired, order1, order2) \ + atomic_compare_exchange_strong_explicit(ptr, expected, desired, order1, order2) +#define ffd_atomic_add_fetch(ptr, val, order) \ + (atomic_fetch_add_explicit(ptr, val, order) + (val)) + +#endif diff --git a/src/corelib/io/forkfd_qt.cpp b/src/corelib/io/forkfd_qt.cpp index 80d1cd54d7..cf44874153 100644 --- a/src/corelib/io/forkfd_qt.cpp +++ b/src/corelib/io/forkfd_qt.cpp @@ -37,37 +37,12 @@ ** ****************************************************************************/ -// these might be defined via precompiled headers -#include +#include #define FORKFD_NO_SPAWNFD - #if defined(QT_NO_DEBUG) && !defined(NDEBUG) # define NDEBUG #endif -typedef QT_PREPEND_NAMESPACE(QBasicAtomicInt) ffd_atomic_int; -#define ffd_atomic_pointer(type) QT_PREPEND_NAMESPACE(QBasicAtomicPointer) - -QT_BEGIN_NAMESPACE - -#define FFD_ATOMIC_INIT(val) Q_BASIC_ATOMIC_INITIALIZER(val) - -#define FFD_ATOMIC_RELAXED Relaxed -#define FFD_ATOMIC_ACQUIRE Acquire -#define FFD_ATOMIC_RELEASE Release - -#define FFD_CONCAT(x, y) x ## y - -#define ffd_atomic_load(ptr,order) (ptr)->FFD_CONCAT(load, order)() -#define ffd_atomic_store(ptr,val,order) (ptr)->FFD_CONCAT(store, order)(val) -#define ffd_atomic_exchange(ptr,val,order) (ptr)->FFD_CONCAT(fetchAndStore, order)(val) -#define ffd_atomic_compare_exchange(ptr,expected,desired,order1,order2) \ - (ptr)->FFD_CONCAT(testAndSet, order1)(*expected, desired, *expected) -#define ffd_atomic_add_fetch(ptr,val,order) ((ptr)->FFD_CONCAT(fetchAndAdd, order)(val) + val) - -QT_END_NAMESPACE - -extern "C" { +#include #include "../../3rdparty/forkfd/forkfd.c" -} -- cgit v1.2.3 From 1b9274573e204ed24ef41eb0dc273bb7aa0be6f2 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sat, 10 Aug 2019 08:13:14 -0700 Subject: forkfd: move the FreeBSD system implementation to a separate file Simplifies the code a bit and will be helpful when I add the Linux equivalent. Change-Id: Iec9c051acd73484c8d94fffd15b99879dc269db9 Reviewed-by: Lars Knoll --- src/3rdparty/forkfd/forkfd.c | 178 ++++++++++++++--------------------- src/3rdparty/forkfd/forkfd_freebsd.c | 101 ++++++++++++++++++++ 2 files changed, 170 insertions(+), 109 deletions(-) create mode 100644 src/3rdparty/forkfd/forkfd_freebsd.c diff --git a/src/3rdparty/forkfd/forkfd.c b/src/3rdparty/forkfd/forkfd.c index 17a9b23581..e4f3bd85de 100644 --- a/src/3rdparty/forkfd/forkfd.c +++ b/src/3rdparty/forkfd/forkfd.c @@ -59,9 +59,6 @@ # define HAVE_PIPE2 1 # endif #endif -#if defined(__FreeBSD__) && __FreeBSD__ >= 9 -# include -#endif #if _POSIX_VERSION-0 >= 200809L || _XOPEN_VERSION-0 >= 500 # define HAVE_WAITID 1 @@ -95,6 +92,10 @@ #include "forkfd_atomic.h" +static int system_has_forkfd(void); +static int system_forkfd(int flags, pid_t *ppid, int *system); +static int system_forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage); + #define CHILDREN_IN_SMALL_ARRAY 16 #define CHILDREN_IN_BIG_ARRAY 256 #define sizeofarray(array) (sizeof(array)/sizeof(array[0])) @@ -446,6 +447,37 @@ static void ignore_sigpipe() #endif } +#if defined(__GNUC__) && (!defined(__FreeBSD__) || __FreeBSD__ < 10) +__attribute((destructor, unused)) static void cleanup(); +#endif + +static void cleanup() +{ + BigArray *array; + /* This function is not thread-safe! + * It must only be called when the process is shutting down. + * At shutdown, we expect no one to be calling forkfd(), so we don't + * need to be thread-safe with what is done there. + * + * But SIGCHLD might be delivered to any thread, including this one. + * There's no way to prevent that. The correct solution would be to + * cooperatively delete. We don't do that. + */ + if (ffd_atomic_load(&forkfd_status, FFD_ATOMIC_RELAXED) == 0) + return; + + /* notify the handler that we're no longer in operation */ + ffd_atomic_store(&forkfd_status, 0, FFD_ATOMIC_RELAXED); + + /* free any arrays we might have */ + array = ffd_atomic_load(&children.header.nextArray, FFD_ATOMIC_ACQUIRE); + while (array != NULL) { + BigArray *next = ffd_atomic_load(&array->header.nextArray, FFD_ATOMIC_ACQUIRE); + free(array); + array = next; + } +} + static void forkfd_initialize() { #if defined(HAVE_BROKEN_WAITID) @@ -487,44 +519,15 @@ static void forkfd_initialize() ignore_sigpipe(); #endif -#ifndef __GNUC__ +#ifdef __GNUC__ + (void) cleanup; /* suppress unused static function warning */ +#else atexit(cleanup); #endif ffd_atomic_store(&forkfd_status, 1, FFD_ATOMIC_RELAXED); } -#ifdef __GNUC__ -__attribute((destructor, unused)) static void cleanup(); -#endif - -static void cleanup() -{ - BigArray *array; - /* This function is not thread-safe! - * It must only be called when the process is shutting down. - * At shutdown, we expect no one to be calling forkfd(), so we don't - * need to be thread-safe with what is done there. - * - * But SIGCHLD might be delivered to any thread, including this one. - * There's no way to prevent that. The correct solution would be to - * cooperatively delete. We don't do that. - */ - if (ffd_atomic_load(&forkfd_status, FFD_ATOMIC_RELAXED) == 0) - return; - - /* notify the handler that we're no longer in operation */ - ffd_atomic_store(&forkfd_status, 0, FFD_ATOMIC_RELAXED); - - /* free any arrays we might have */ - array = ffd_atomic_load(&children.header.nextArray, FFD_ATOMIC_ACQUIRE); - while (array != NULL) { - BigArray *next = ffd_atomic_load(&array->header.nextArray, FFD_ATOMIC_ACQUIRE); - free(array); - array = next; - } -} - static int create_pipe(int filedes[], int flags) { int ret = -1; @@ -563,55 +566,6 @@ static int create_pipe(int filedes[], int flags) return ret; } -#if defined(FORKFD_NO_SPAWNFD) && defined(__FreeBSD__) && __FreeBSD__ >= 9 -# if __FreeBSD__ == 9 -/* PROCDESC is an optional feature in the kernel and wasn't enabled - * by default on FreeBSD 9. So we need to check for it at runtime. */ -static ffd_atomic_int system_has_forkfd = FFD_ATOMIC_INIT(1); -# else -/* On FreeBSD 10, PROCDESC was enabled by default. On v11, it's not an option - * anymore and can't be disabled. */ -static const int system_has_forkfd = 1; -# endif - -static int system_forkfd(int flags, pid_t *ppid) -{ - int ret; - pid_t pid; - pid = pdfork(&ret, PD_DAEMON); - if (__builtin_expect(pid == -1, 0)) { -# if __FreeBSD__ == 9 - if (errno == ENOSYS) { - /* PROCDESC wasn't compiled into the kernel: don't try it again. */ - ffd_atomic_store(&system_has_forkfd, 0, FFD_ATOMIC_RELAXED); - } -# endif - return -1; - } - if (pid == 0) { - /* child process */ - return FFD_CHILD_PROCESS; - } - - /* parent process */ - if (flags & FFD_CLOEXEC) - fcntl(ret, F_SETFD, FD_CLOEXEC); - if (flags & FFD_NONBLOCK) - fcntl(ret, F_SETFL, fcntl(ret, F_GETFL) | O_NONBLOCK); - if (ppid) - *ppid = pid; - return ret; -} -#else -static const int system_has_forkfd = 0; -static int system_forkfd(int flags, pid_t *ppid) -{ - (void)flags; - (void)ppid; - return -1; -} -#endif - #ifndef FORKFD_NO_FORKFD /** * @brief forkfd returns a file descriptor representing a child process @@ -659,11 +613,9 @@ int forkfd(int flags, pid_t *ppid) int efd; #endif - if (system_has_forkfd) { - ret = system_forkfd(flags, ppid); - if (system_has_forkfd) - return ret; - } + fd = system_forkfd(flags, ppid, &ret); + if (ret) + return fd; (void) pthread_once(&forkfd_initialization, forkfd_initialize); @@ -788,7 +740,7 @@ int spawnfd(int flags, pid_t *ppid, const char *path, const posix_spawn_file_act /* we can only do work if we have a way to start the child in stopped mode; * otherwise, we have a major race condition. */ - assert(!system_has_forkfd); + assert(!system_has_forkfd()); (void) pthread_once(&forkfd_initialization, forkfd_initialize); @@ -846,25 +798,8 @@ int forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage) struct pipe_payload payload; int ret; - if (system_has_forkfd) { -#if defined(__FreeBSD__) && __FreeBSD__ >= 9 - pid_t pid; - int status; - int options = WEXITED; - - ret = pdgetpid(ffd, &pid); - if (ret == -1) - return ret; - ret = fcntl(ffd, F_GETFL); - if (ret == -1) - return ret; - options |= (ret & O_NONBLOCK) ? WNOHANG : 0; - ret = wait4(pid, &status, options, rusage); - if (ret != -1 && info) - convertStatusToForkfdInfo(status, info); - return ret == -1 ? -1 : 0; -#endif - } + if (system_has_forkfd()) + return system_forkfd_wait(ffd, info, rusage); ret = read(ffd, &payload, sizeof(payload)); if (ret == -1) @@ -884,3 +819,28 @@ int forkfd_close(int ffd) { return close(ffd); } + +#if defined(__FreeBSD__) && __FreeBSD__ >= 9 +# include "forkfd_freebsd.c" +#else +int system_has_forkfd() +{ + return 0; +} + +int system_forkfd(int flags, pid_t *ppid, int *system) +{ + (void)flags; + (void)ppid; + *system = 0; + return -1; +} + +int system_forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage) +{ + (void)ffd; + (void)info; + (void)rusage; + return -1; +} +#endif diff --git a/src/3rdparty/forkfd/forkfd_freebsd.c b/src/3rdparty/forkfd/forkfd_freebsd.c new file mode 100644 index 0000000000..77ce3fcfad --- /dev/null +++ b/src/3rdparty/forkfd/forkfd_freebsd.c @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Intel Corporation. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#include "forkfd.h" + +#include +#include + +#include "forkfd_atomic.h" + +#if __FreeBSD__ >= 10 +/* On FreeBSD 10, PROCDESC was enabled by default. On v11, it's not an option + * anymore and can't be disabled. */ +static ffd_atomic_int system_forkfd_state = FFD_ATOMIC_INIT(1); +#else +static ffd_atomic_int system_forkfd_state = FFD_ATOMIC_INIT(0); +#endif + +int system_has_forkfd() +{ + return ffd_atomic_load(&system_forkfd_state, FFD_ATOMIC_RELAXED) > 0; +} + +int system_forkfd(int flags, pid_t *ppid, int *system) +{ + int ret; + pid_t pid; + + int state = ffd_atomic_load(&system_forkfd_state, FFD_ATOMIC_RELAXED); + *system = 0; + if (state < 0) + return -1; + + pid = pdfork(&ret, PD_DAEMON); +# if __FreeBSD__ == 9 + if (state == 0 && pid != 0) { + /* Parent process: remember whether PROCDESC was compiled into the kernel */ + state = (pid == -1 && errno == ENOSYS) ? -1 : 1; + ffd_atomic_store(&system_forkfd_state, state, FFD_ATOMIC_RELAXED); + } + if (state < 0) + return -1; +# endif + *system = 1; + if (__builtin_expect(pid == -1, 0)) + return -1; + + if (pid == 0) { + /* child process */ + return FFD_CHILD_PROCESS; + } + + /* parent process */ + if (flags & FFD_CLOEXEC) + fcntl(ret, F_SETFD, FD_CLOEXEC); + if (flags & FFD_NONBLOCK) + fcntl(ret, F_SETFL, fcntl(ret, F_GETFL) | O_NONBLOCK); + if (ppid) + *ppid = pid; + return ret; +} + +int system_forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage) +{ + pid_t pid; + int status; + int options = WEXITED; + + int ret = pdgetpid(ffd, &pid); + if (ret == -1) + return ret; + ret = fcntl(ffd, F_GETFL); + if (ret == -1) + return ret; + options |= (ret & O_NONBLOCK) ? WNOHANG : 0; + ret = wait4(pid, &status, options, rusage); + if (ret != -1 && info) + convertStatusToForkfdInfo(status, info); + return ret == -1 ? -1 : 0; +} -- cgit v1.2.3 From fb462102b70024f518b004b9e08a6987a2bab5bd Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 20 Aug 2019 14:49:37 +0200 Subject: QHttp2Configuration - respect the value returned by huffmanCompressionEnabled() And either compress or not. Task-number: QTBUG-77412 Change-Id: I3b09385d2b3caf4f7de0455ad6e22c0f068c33a9 Reviewed-by: Volker Hilsheimer --- src/network/access/http2/hpack.cpp | 5 +++++ src/network/access/http2/hpack_p.h | 1 + src/network/access/qhttp2protocolhandler.cpp | 1 + 3 files changed, 7 insertions(+) diff --git a/src/network/access/http2/hpack.cpp b/src/network/access/http2/hpack.cpp index 2d324d5092..b40cc29e1a 100644 --- a/src/network/access/http2/hpack.cpp +++ b/src/network/access/http2/hpack.cpp @@ -208,6 +208,11 @@ void Encoder::setMaxDynamicTableSize(quint32 size) lookupTable.setMaxDynamicTableSize(size); } +void Encoder::setCompressStrings(bool compress) +{ + compressStrings = compress; +} + bool Encoder::encodeRequestPseudoHeaders(BitOStream &outputStream, const HttpHeader &header) { diff --git a/src/network/access/http2/hpack_p.h b/src/network/access/http2/hpack_p.h index 6a1d30d87b..8c2701e7af 100644 --- a/src/network/access/http2/hpack_p.h +++ b/src/network/access/http2/hpack_p.h @@ -83,6 +83,7 @@ public: quint32 newSize); void setMaxDynamicTableSize(quint32 size); + void setCompressStrings(bool compress); private: bool encodeRequestPseudoHeaders(BitOStream &outputStream, diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp index b8a415000a..c1053882af 100644 --- a/src/network/access/qhttp2protocolhandler.cpp +++ b/src/network/access/qhttp2protocolhandler.cpp @@ -179,6 +179,7 @@ QHttp2ProtocolHandler::QHttp2ProtocolHandler(QHttpNetworkConnectionChannel *chan maxSessionReceiveWindowSize = h2Config.sessionReceiveWindowSize(); pushPromiseEnabled = h2Config.serverPushEnabled(); streamInitialReceiveWindowSize = h2Config.streamReceiveWindowSize(); + encoder.setCompressStrings(h2Config.huffmanCompressionEnabled()); if (!channel->ssl && m_connection->connectionType() != QHttpNetworkConnection::ConnectionTypeHTTP2Direct) { // We upgraded from HTTP/1.1 to HTTP/2. channel->request was already sent -- cgit v1.2.3 From 4c6e549b250b834b43473aa3d748d625449df42c Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 20 Aug 2019 14:55:54 +0200 Subject: QHttp2Configuration: remove setters/getter for indexing Upon reading the Apple's documentation it would appear the indexing is more complicated (they name the specific fields and which kind of indexing must be applied to each). This requires a finer level of configuration/control and probably a separate class (aka QHpackConfiguration? ;). We'll provide it in future, if requested by our users. Fixes: QTBUG-77412 Change-Id: I6e9461b3966ed59c8b70873eab999a07a04eb289 Reviewed-by: Volker Hilsheimer --- src/network/access/qhttp2configuration.cpp | 37 +++--------------------------- src/network/access/qhttp2configuration.h | 3 --- 2 files changed, 3 insertions(+), 37 deletions(-) diff --git a/src/network/access/qhttp2configuration.cpp b/src/network/access/qhttp2configuration.cpp index 14c9d6dc29..a32bccfd09 100644 --- a/src/network/access/qhttp2configuration.cpp +++ b/src/network/access/qhttp2configuration.cpp @@ -79,13 +79,9 @@ QT_BEGIN_NAMESPACE frame. \endlist - The QHttp2Configuration class also controls some of the parameters - affecting the header compression algorithm (HPACK). They include: - - \list - \li Huffman string compression. - \li Indexing strings. - \endlist + The QHttp2Configuration class also controls if the header compression + algorithm (HPACK) is additionally using Huffman coding for string + compression. \note The configuration must be set before the first request was sent to a given host (and thus an HTTP/2 session established). @@ -112,7 +108,6 @@ public: bool pushEnabled = false; // TODO: for now those two below are noop. bool huffmanCompressionEnabled = true; - bool indexingEnabled = true; }; /*! @@ -122,7 +117,6 @@ public: \list \li Server push is disabled \li Huffman string compression is enabled - \li String indexing is enabled \li Window size for connection-level flow control is 65535 octets \li Window size for stream-level flow control is 65535 octets \li Frame size is 16384 octets @@ -211,30 +205,6 @@ bool QHttp2Configuration::huffmanCompressionEnabled() const return d->huffmanCompressionEnabled; } -/*! - If \a enable is \c true, HPACK compression will index strings - in its dynamic compression table. Enabled by default. - - \note This setting only has an affect on how QNetworkAccessManager - sending 'HEADERS' frames. - - \sa stringIndexingEnabled -*/ -void QHttp2Configuration::setStringIndexingEnabled(bool enable) -{ - d->indexingEnabled = enable; -} - -/*! - Returns \true if HPACK compression is indexing strings. - - \sa setStringIndexingEnabled -*/ -bool QHttp2Configuration::stringIndexingEnabled() const -{ - return d->indexingEnabled; -} - /*! Sets the window size for connection-level flow control. \a size cannot be 0 and must not exceed 2147483647 octets. @@ -335,7 +305,6 @@ bool operator==(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs) return lhs.d->pushEnabled == rhs.d->pushEnabled && lhs.d->huffmanCompressionEnabled == rhs.d->huffmanCompressionEnabled - && lhs.d->indexingEnabled == rhs.d->indexingEnabled && lhs.d->sessionWindowSize == rhs.d->sessionWindowSize && lhs.d->streamWindowSize == rhs.d->streamWindowSize; } diff --git a/src/network/access/qhttp2configuration.h b/src/network/access/qhttp2configuration.h index 2a5e8c9341..544e3a3d98 100644 --- a/src/network/access/qhttp2configuration.h +++ b/src/network/access/qhttp2configuration.h @@ -66,9 +66,6 @@ public: void setHuffmanCompressionEnabled(bool enable); bool huffmanCompressionEnabled() const; - void setStringIndexingEnabled(bool enable); - bool stringIndexingEnabled() const; - bool setSessionReceiveWindowSize(unsigned size); unsigned sessionReceiveWindowSize() const; -- cgit v1.2.3 From c8c724a3ce223724f0d164f38415ba1afaca53b8 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 13 Aug 2019 16:42:48 +0200 Subject: Cbor: Add overloads for QStringView Change-Id: I8d22d0741c4d3852b438b12099f81ed87244871d Reviewed-by: Thiago Macieira --- src/corelib/serialization/qcborvalue.cpp | 16 +++++++-- src/corelib/serialization/qcborvalue.h | 3 ++ src/corelib/serialization/qcborvalue_p.h | 56 ++++++++++++++++++++------------ 3 files changed, 52 insertions(+), 23 deletions(-) diff --git a/src/corelib/serialization/qcborvalue.cpp b/src/corelib/serialization/qcborvalue.cpp index ba616c0a7d..9053618014 100644 --- a/src/corelib/serialization/qcborvalue.cpp +++ b/src/corelib/serialization/qcborvalue.cpp @@ -915,7 +915,7 @@ void QCborContainerPrivate::replaceAt_complex(Element &e, const QCborValue &valu // in qstring.cpp void qt_to_latin1_unchecked(uchar *dst, const ushort *uc, qsizetype len); -Q_NEVER_INLINE void QCborContainerPrivate::appendAsciiString(const QString &s) +Q_NEVER_INLINE void QCborContainerPrivate::appendAsciiString(QStringView s) { qsizetype len = s.size(); QtCbor::Element e; @@ -926,7 +926,7 @@ Q_NEVER_INLINE void QCborContainerPrivate::appendAsciiString(const QString &s) char *ptr = data.data() + e.value + sizeof(ByteData); uchar *l = reinterpret_cast(ptr); - const ushort *uc = (const ushort *)s.unicode(); + const ushort *uc = (const ushort *)s.utf16(); qt_to_latin1_unchecked(l, uc, len); } @@ -1646,13 +1646,23 @@ QCborValue::QCborValue(const QByteArray &ba) container->ref.storeRelaxed(1); } +#if QT_STRINGVIEW_LEVEL < 2 /*! Creates a QCborValue with string value \a s. The value can later be retrieved using toString(). \sa toString(), isString(), isByteArray() */ -QCborValue::QCborValue(const QString &s) +QCborValue::QCborValue(const QString &s) : QCborValue(qToStringViewIgnoringNull(s)) {} +#endif + +/*! + Creates a QCborValue with string value \a s. The value can later be + retrieved using toString(). + + \sa toString(), isString(), isByteArray() +*/ +QCborValue::QCborValue(QStringView s) : n(0), container(new QCborContainerPrivate), t(String) { container->append(s); diff --git a/src/corelib/serialization/qcborvalue.h b/src/corelib/serialization/qcborvalue.h index f542e44c47..f79fc572c4 100644 --- a/src/corelib/serialization/qcborvalue.h +++ b/src/corelib/serialization/qcborvalue.h @@ -143,7 +143,10 @@ public: QCborValue(QCborSimpleType st) : t(type_helper(st)) {} QCborValue(const QByteArray &ba); +#if QT_STRINGVIEW_LEVEL < 2 QCborValue(const QString &s); +#endif + QCborValue(QStringView s); QCborValue(QLatin1String s); #ifndef QT_NO_CAST_FROM_ASCII QT_ASCII_CAST_WARN QCborValue(const char *s) : QCborValue(QString::fromUtf8(s)) {} diff --git a/src/corelib/serialization/qcborvalue_p.h b/src/corelib/serialization/qcborvalue_p.h index 4050d18fa9..590c2d6e05 100644 --- a/src/corelib/serialization/qcborvalue_p.h +++ b/src/corelib/serialization/qcborvalue_p.h @@ -245,13 +245,21 @@ public: appendByteData(s.latin1(), s.size(), QCborValue::String, QtCbor::Element::StringIsAscii); } - void appendAsciiString(const QString &s); + void appendAsciiString(QStringView s); + +#if QT_STRINGVIEW_LEVEL < 2 void append(const QString &s) + { + append(qToStringViewIgnoringNull(s)); + } +#endif + + void append(QStringView s) { if (QtPrivate::isAscii(s)) appendAsciiString(s); else - appendByteData(reinterpret_cast(s.constData()), s.size() * 2, + appendByteData(reinterpret_cast(s.utf16()), s.size() * 2, QCborValue::String, QtCbor::Element::StringIsUtf16); } void append(const QCborValue &v) @@ -345,33 +353,41 @@ public: return e; } - bool stringEqualsElement(qsizetype idx, QLatin1String s) const + static int compareUtf8(const QtCbor::ByteData *b, const QLatin1String &s) { - const auto &e = elements.at(idx); - if (e.type != QCborValue::String) - return false; - - const QtCbor::ByteData *b = byteData(idx); - if (!b) - return s.isEmpty(); + return QUtf8::compareUtf8(b->byte(), b->len, s); + } - if (e.flags & QtCbor::Element::StringIsUtf16) - return QtPrivate::compareStrings(b->asStringView(), s) == 0; - return QUtf8::compareUtf8(b->byte(), b->len, s) == 0; + static int compareUtf8(const QtCbor::ByteData *b, QStringView s) + { + return QUtf8::compareUtf8(b->byte(), b->len, s.data(), s.size()); } - bool stringEqualsElement(qsizetype idx, const QString &s) const + + template + int stringCompareElement(const QtCbor::Element &e, String s) const { - const auto &e = elements.at(idx); if (e.type != QCborValue::String) - return false; + return int(e.type) - int(QCborValue::String); - const QtCbor::ByteData *b = byteData(idx); + const QtCbor::ByteData *b = byteData(e); if (!b) - return s.isEmpty(); + return s.isEmpty() ? 0 : -1; if (e.flags & QtCbor::Element::StringIsUtf16) - return QtPrivate::compareStrings(b->asStringView(), s) == 0; - return QUtf8::compareUtf8(b->byte(), b->len, s.data(), s.size()) == 0; + return QtPrivate::compareStrings(b->asStringView(), s); + return compareUtf8(b, s); + } + + template + bool stringEqualsElement(const QtCbor::Element &e, String s) const + { + return stringCompareElement(e, s) == 0; + } + + template + bool stringEqualsElement(qsizetype idx, String s) const + { + return stringEqualsElement(elements.at(idx), s); } static int compareElement_helper(const QCborContainerPrivate *c1, QtCbor::Element e1, -- cgit v1.2.3 From 62015adadd17a46c32e350c657f244d8a7515863 Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Sat, 17 Aug 2019 14:13:50 +0200 Subject: QFont: remove unused member QFontPrivate::screen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QFontPrivate::screen was not used anywhere so remove it. Change-Id: Ie9381d08b59b93c4e7bcaad58ebf1b389aa0a2e6 Reviewed-by: Thorbjørn Lund Martsum Reviewed-by: Konstantin Ritt Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/text/qfont.cpp | 8 +++----- src/gui/text/qfont_p.h | 10 +++------- src/gui/text/qfontmetrics.cpp | 8 ++------ 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index 97e73f0723..3c1a052f37 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -180,14 +180,14 @@ Q_GUI_EXPORT int qt_defaultDpi() } QFontPrivate::QFontPrivate() - : engineData(0), dpi(qt_defaultDpi()), screen(0), + : engineData(0), dpi(qt_defaultDpi()), underline(false), overline(false), strikeOut(false), kerning(true), capital(0), letterSpacingIsAbsolute(false), scFont(0) { } QFontPrivate::QFontPrivate(const QFontPrivate &other) - : request(other.request), engineData(0), dpi(other.dpi), screen(other.screen), + : request(other.request), engineData(0), dpi(other.dpi), underline(other.underline), overline(other.overline), strikeOut(other.strikeOut), kerning(other.kerning), capital(other.capital), letterSpacingIsAbsolute(other.letterSpacingIsAbsolute), @@ -581,11 +581,9 @@ QFont::QFont(const QFont &font, const QPaintDevice *pd) { Q_ASSERT(pd); const int dpi = pd->logicalDpiY(); - const int screen = 0; - if (font.d->dpi != dpi || font.d->screen != screen ) { + if (font.d->dpi != dpi) { d = new QFontPrivate(*font.d); d->dpi = dpi; - d->screen = screen; } else { d = font.d; } diff --git a/src/gui/text/qfont_p.h b/src/gui/text/qfont_p.h index 466e19e9cc..adbb7a0121 100644 --- a/src/gui/text/qfont_p.h +++ b/src/gui/text/qfont_p.h @@ -185,7 +185,6 @@ public: QFontDef request; mutable QFontEngineData *engineData; int dpi; - int screen; uint underline : 1; uint overline : 1; @@ -230,19 +229,17 @@ public: void clear(); struct Key { - Key() : script(0), multi(0), screen(0) { } - Key(const QFontDef &d, uchar c, bool m = 0, uchar s = 0) - : def(d), script(c), multi(m), screen(s) { } + Key() : script(0), multi(0) { } + Key(const QFontDef &d, uchar c, bool m = 0) + : def(d), script(c), multi(m) { } QFontDef def; uchar script; uchar multi: 1; - uchar screen: 7; inline bool operator<(const Key &other) const { if (script != other.script) return script < other.script; - if (screen != other.screen) return screen < other.screen; if (multi != other.multi) return multi < other.multi; if (multi && def.fallBackFamilies.size() != other.def.fallBackFamilies.size()) return def.fallBackFamilies.size() < other.def.fallBackFamilies.size(); @@ -251,7 +248,6 @@ public: inline bool operator==(const Key &other) const { return script == other.script - && screen == other.screen && multi == other.multi && (!multi || def.fallBackFamilies == other.def.fallBackFamilies) && def == other.def; diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp index c8dc8d676e..7096bba160 100644 --- a/src/gui/text/qfontmetrics.cpp +++ b/src/gui/text/qfontmetrics.cpp @@ -185,11 +185,9 @@ QFontMetrics::QFontMetrics(const QFont &font, const QPaintDevice *paintdevice) #endif { const int dpi = paintdevice ? paintdevice->logicalDpiY() : qt_defaultDpi(); - const int screen = 0; - if (font.d->dpi != dpi || font.d->screen != screen ) { + if (font.d->dpi != dpi) { d = new QFontPrivate(*font.d); d->dpi = dpi; - d->screen = screen; } else { d = font.d; } @@ -1171,11 +1169,9 @@ QFontMetricsF::QFontMetricsF(const QFont &font, const QPaintDevice *paintdevice) #endif { int dpi = paintdevice ? paintdevice->logicalDpiY() : qt_defaultDpi(); - const int screen = 0; - if (font.d->dpi != dpi || font.d->screen != screen ) { + if (font.d->dpi != dpi) { d = new QFontPrivate(*font.d); d->dpi = dpi; - d->screen = screen; } else { d = font.d; } -- cgit v1.2.3 From d97009a9f147af7f9785afb53df49e874aadd969 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Sun, 11 Aug 2019 08:59:07 +0200 Subject: Remove obsolete API after qtdeclarative migrated This is a follow-up to commit b7d073e9905bf9812ba96cecdcf6871a95517d30, which refactored memory allocation of QMetaCallEvent. Change-Id: I363256c80ee941b545e6f9c659c65556fff5c907 Reviewed-by: Simon Hausmann --- src/corelib/kernel/qobject.cpp | 22 ---------------------- src/corelib/kernel/qobject_p.h | 6 ------ 2 files changed, 28 deletions(-) diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 4a26e9cdc0..9251a3c05f 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -524,28 +524,6 @@ inline void QMetaCallEvent::allocArgs() d.args_ = static_cast(memory); } -/*! - \internal - - Only used by QtDeclarative - to be removed when migrated. - */ -QMetaCallEvent::QMetaCallEvent(ushort method_offset, ushort method_relative, - QObjectPrivate::StaticMetaCallFunction callFunction, - const QObject *sender, int signalId, - int nargs, int *types_, void **args_) - : QAbstractMetaCallEvent(sender, signalId), - d({nullptr, nullptr, callFunction, nargs, method_offset, method_relative}), - prealloc_() -{ - allocArgs(); - for (int arg = 0; arg < nargs; ++arg) { - types()[arg] = types_[arg]; - args()[arg] = args_[arg]; - } - free(types_); - free(args_); -} - /*! \internal diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index 5d0b3a8399..feafcaf323 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -509,12 +509,6 @@ private: class Q_CORE_EXPORT QMetaCallEvent : public QAbstractMetaCallEvent { public: - // kept for compatibility until QtDeclarative has moved over - QMetaCallEvent(ushort method_offset, ushort method_relative, - QObjectPrivate::StaticMetaCallFunction callFunction, - const QObject *sender, int signalId, - int nargs, int *types, void **args); - // blocking queued with semaphore - args always owned by caller QMetaCallEvent(ushort method_offset, ushort method_relative, QObjectPrivate::StaticMetaCallFunction callFunction, -- cgit v1.2.3 From 6a2112c28c0dcc79a83607f87eec8fbd75440798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Wed, 14 Aug 2019 12:00:13 +0200 Subject: Remove use of QByteDataBuffer in QNetworkReplyHttpImpl It's temporarily storing QByteArrays before we copy them directly to QIODevice's internal buffer. We can save the extra work by just push them directly into the buffer. The signal compression is no longer useful performance-wise, but is kept as it will throttle the amount of readyRead emissions the users has to handle. Reorder some of the operations as a result to make it more natural. Change-Id: Ifc0481d56fec42545e95970125d883a5c68d647a Reviewed-by: Alex Trotsenko Reviewed-by: Timur Pocheptsov --- src/network/access/qnetworkreplyhttpimpl.cpp | 58 +++++++++------------------- src/network/access/qnetworkreplyhttpimpl_p.h | 2 - 2 files changed, 19 insertions(+), 41 deletions(-) diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 12dfb1c269..b3dec282b0 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -1052,59 +1052,39 @@ void QNetworkReplyHttpImplPrivate::replyDownloadData(QByteArray d) if (!q->isOpen()) return; - int pendingSignals = (int)pendingDownloadDataEmissions->fetchAndAddAcquire(-1) - 1; + if (cacheEnabled && isCachingAllowed() && !cacheSaveDevice) + initCacheSaveDevice(); + + // This is going to look a little strange. When downloading data while a + // HTTP redirect is happening (and enabled), we write the redirect + // response to the cache. However, we do not append it to our internal + // buffer as that will contain the response data only for the final + // response + if (cacheSaveDevice) + cacheSaveDevice->write(d); + + if (!isHttpRedirectResponse()) { + buffer.append(d); + bytesDownloaded += d.size(); + } + bytesBuffered += d.size(); + int pendingSignals = pendingDownloadDataEmissions->fetchAndSubAcquire(1) - 1; if (pendingSignals > 0) { // Some more signal emissions to this slot are pending. // Instead of writing the downstream data, we wait // and do it in the next call we get // (signal comppression) - pendingDownloadData.append(d); return; } - pendingDownloadData.append(d); - d.clear(); - // We need to usa a copy for calling writeDownstreamData as we could - // possibly recurse into this this function when we call - // appendDownstreamDataSignalEmissions because the user might call - // processEvents() or spin an event loop when this occur. - QByteDataBuffer pendingDownloadDataCopy = pendingDownloadData; - pendingDownloadData.clear(); - - if (cacheEnabled && isCachingAllowed() && !cacheSaveDevice) { - initCacheSaveDevice(); - } - - qint64 bytesWritten = 0; - for (int i = 0; i < pendingDownloadDataCopy.bufferCount(); i++) { - QByteArray const &item = pendingDownloadDataCopy[i]; - - // This is going to look a little strange. When downloading data while a - // HTTP redirect is happening (and enabled), we write the redirect - // response to the cache. However, we do not append it to our internal - // buffer as that will contain the response data only for the final - // response - if (cacheSaveDevice) - cacheSaveDevice->write(item.constData(), item.size()); - - if (!isHttpRedirectResponse()) - buffer.append(item); - - bytesWritten += item.size(); - } - bytesBuffered += bytesWritten; - pendingDownloadDataCopy.clear(); + if (isHttpRedirectResponse()) + return; QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader); if (preMigrationDownloaded != Q_INT64_C(-1)) totalSize = totalSize.toLongLong() + preMigrationDownloaded; - if (isHttpRedirectResponse()) - return; - - bytesDownloaded += bytesWritten; - emit q->readyRead(); // emit readyRead before downloadProgress incase this will cause events to be // processed and we get into a recursive call (as in QProgressDialog). diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h index f5f01d0811..ef69ce0653 100644 --- a/src/network/access/qnetworkreplyhttpimpl_p.h +++ b/src/network/access/qnetworkreplyhttpimpl_p.h @@ -63,7 +63,6 @@ #include #include -#include #include #include #include @@ -248,7 +247,6 @@ public: quint64 resumeOffset; qint64 preMigrationDownloaded; - QByteDataBuffer pendingDownloadData; // For signal compression qint64 bytesDownloaded; qint64 bytesBuffered; -- cgit v1.2.3 From 9db230efa92fec992132fcf7e4bb7fda9707b152 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Mon, 19 Aug 2019 09:17:24 +0200 Subject: Fix "conflicting targets" warning when generating VS projects The VS project generator never calls the Win32MakefileGenerator code that sets up DEST_TARGET which is used for checking for conflicting DESTDIR/TARGET combinations on Windows. Replicate the setup in VcprojGenerator::initProject(). This amends commit e75aed1a. Change-Id: I4238eb2f57615095c372cee9ada9fc961cc36133 Reviewed-by: Alexandru Croitor --- qmake/generators/win32/msvc_vcproj.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp index 06db24df22..b74448ce94 100644 --- a/qmake/generators/win32/msvc_vcproj.cpp +++ b/qmake/generators/win32/msvc_vcproj.cpp @@ -940,6 +940,15 @@ void VcprojGenerator::initProject() vcProject.SccProjectName = project->first("SCCPROJECTNAME").toQString(); vcProject.SccLocalPath = project->first("SCCLOCALPATH").toQString(); vcProject.flat_files = project->isActiveConfig("flat"); + + // Set up the full target path for target conflict checking. + const QChar slash = QLatin1Char('/'); + QString destdir = QDir::fromNativeSeparators(var("DESTDIR")); + if (!destdir.endsWith(slash)) + destdir.append(slash); + project->values("DEST_TARGET") = ProStringList(destdir + + project->first("TARGET") + + project->first("TARGET_EXT")); } void VcprojGenerator::initConfiguration() -- cgit v1.2.3 From 4300dccba56ed1904c3481a4b19fdc5475f6b3e1 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Thu, 22 Aug 2019 09:43:26 +0200 Subject: Fix a broken build QHttp2Configuration is using entities (read definitions) from http2, which is only conditionally included in the *.pri file (requires http). So as a result we had linker errors. Fixes: QTBUG-77759 Change-Id: I8b33b0a4802a295f67edad03da3743b24f7ce514 Reviewed-by: Eskil Abrahamsen Blomfeldt Reviewed-by: Paul Wicking --- src/network/access/access.pri | 12 ++++++------ src/network/access/qhttp2configuration.h | 4 ++++ src/network/access/qnetworkrequest.cpp | 17 +++++++++++++++-- src/network/access/qnetworkrequest.h | 3 ++- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/network/access/access.pri b/src/network/access/access.pri index 87fb82b1a7..cfb20dcd71 100644 --- a/src/network/access/access.pri +++ b/src/network/access/access.pri @@ -24,8 +24,7 @@ HEADERS += \ access/qabstractnetworkcache.h \ access/qnetworkfile_p.h \ access/qhsts_p.h \ - access/qhstspolicy.h \ - access/qhttp2configuration.h + access/qhstspolicy.h SOURCES += \ access/qnetworkaccessauthenticationmanager.cpp \ @@ -45,8 +44,7 @@ SOURCES += \ access/qabstractnetworkcache.cpp \ access/qnetworkfile.cpp \ access/qhsts.cpp \ - access/qhstspolicy.cpp \ - access/qhttp2configuration.cpp + access/qhstspolicy.cpp qtConfig(ftp) { HEADERS += \ @@ -99,7 +97,8 @@ qtConfig(http) { access/qhttpnetworkrequest.cpp \ access/qhttpprotocolhandler.cpp \ access/qhttpthreaddelegate.cpp \ - access/qnetworkreplyhttpimpl.cpp + access/qnetworkreplyhttpimpl.cpp \ + access/qhttp2configuration.cpp HEADERS += \ access/qabstractprotocolhandler_p.h \ @@ -113,7 +112,8 @@ qtConfig(http) { access/qhttpnetworkrequest_p.h \ access/qhttpprotocolhandler_p.h \ access/qhttpthreaddelegate_p.h \ - access/qnetworkreplyhttpimpl_p.h + access/qnetworkreplyhttpimpl_p.h \ + access/qhttp2configuration.h qtConfig(ssl) { SOURCES += \ diff --git a/src/network/access/qhttp2configuration.h b/src/network/access/qhttp2configuration.h index 544e3a3d98..e5c235e2be 100644 --- a/src/network/access/qhttp2configuration.h +++ b/src/network/access/qhttp2configuration.h @@ -44,6 +44,10 @@ #include +#ifndef Q_CLANG_QDOC +QT_REQUIRE_CONFIG(http); +#endif + QT_BEGIN_NAMESPACE class QHttp2ConfigurationPrivate; diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index e3976db642..118fb6b1fb 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -42,8 +42,10 @@ #include "qplatformdefs.h" #include "qnetworkcookie.h" #include "qsslconfiguration.h" +#if QT_CONFIG(http) || defined(Q_CLANG_QDOC) #include "qhttp2configuration.h" #include "private/http2protocol_p.h" +#endif #include "QtCore/qshareddata.h" #include "QtCore/qlocale.h" #include "QtCore/qdatetime.h" @@ -447,7 +449,9 @@ public: sslConfiguration = new QSslConfiguration(*other.sslConfiguration); #endif peerVerifyName = other.peerVerifyName; +#if QT_CONFIG(http) h2Configuration = other.h2Configuration; +#endif } inline bool operator==(const QNetworkRequestPrivate &other) const @@ -457,8 +461,11 @@ public: rawHeaders == other.rawHeaders && attributes == other.attributes && maxRedirectsAllowed == other.maxRedirectsAllowed && - peerVerifyName == other.peerVerifyName && - h2Configuration == other.h2Configuration; + peerVerifyName == other.peerVerifyName +#if QT_CONFIG(http) + && h2Configuration == other.h2Configuration +#endif + ; // don't compare cookedHeaders } @@ -469,7 +476,9 @@ public: #endif int maxRedirectsAllowed; QString peerVerifyName; +#if QT_CONFIG(http) QHttp2Configuration h2Configuration; +#endif }; /*! @@ -481,6 +490,7 @@ public: QNetworkRequest::QNetworkRequest() : d(new QNetworkRequestPrivate) { +#if QT_CONFIG(http) // Initial values proposed by RFC 7540 are quite draconian, // so unless an application will set its own parameters, we // make stream window size larger and increase (via WINDOW_UPDATE) @@ -488,6 +498,7 @@ QNetworkRequest::QNetworkRequest() d->h2Configuration.setStreamReceiveWindowSize(Http2::qtDefaultStreamReceiveWindowSize); d->h2Configuration.setSessionReceiveWindowSize(Http2::maxSessionReceiveWindowSize); d->h2Configuration.setServerPushEnabled(false); +#endif // QT_CONFIG(http) } /*! @@ -847,6 +858,7 @@ void QNetworkRequest::setPeerVerifyName(const QString &peerName) d->peerVerifyName = peerName; } +#if QT_CONFIG(http) || defined(Q_CLANG_QDOC) /*! \since 5.14 @@ -890,6 +902,7 @@ void QNetworkRequest::setHttp2Configuration(const QHttp2Configuration &configura { d->h2Configuration = configuration; } +#endif // QT_CONFIG(http) || defined(Q_CLANG_QDOC) static QByteArray headerName(QNetworkRequest::KnownHeaders header) { diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h index 463dabef83..e09ff8aaae 100644 --- a/src/network/access/qnetworkrequest.h +++ b/src/network/access/qnetworkrequest.h @@ -176,9 +176,10 @@ public: QString peerVerifyName() const; void setPeerVerifyName(const QString &peerName); - +#if QT_CONFIG(http) || defined(Q_CLANG_QDOC) QHttp2Configuration http2Configuration() const; void setHttp2Configuration(const QHttp2Configuration &configuration); +#endif // QT_CONFIG(http) || defined(Q_CLANG_QDOC) private: QSharedDataPointer d; friend class QNetworkRequestPrivate; -- cgit v1.2.3 From 529b27152068f02fc67dba6e4bb88be918220827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Thu, 22 Aug 2019 10:18:53 +0200 Subject: Don't excessively check all output files for failures This is really just an optimization, but I suspect the author of the code assumed that the bitwise &= operator short-cicuits. (It doesn't). So this patch should then fix the code to have the intended behavior. We don't have to check for failures in the remaining output files once we've found one. pullFiles() returns just a bool indicating if one of the output files has a recorded fail, so checking the remaining output files after the first found failure is just a waste (and ideally they should contain the same failure (however, flaky tests might break this ideal)). Drive-by fix. Change-Id: I951e500a69198e7ed124be32199ac81bbddb9bf7 Reviewed-by: BogDan Vatra --- src/tools/androidtestrunner/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/androidtestrunner/main.cpp b/src/tools/androidtestrunner/main.cpp index a035e068bc..f61d407d4a 100644 --- a/src/tools/androidtestrunner/main.cpp +++ b/src/tools/androidtestrunner/main.cpp @@ -409,7 +409,7 @@ static bool pullFiles() return false; } auto checkerIt = g_options.checkFiles.find(it.key()); - ret &= checkerIt != g_options.checkFiles.end() && checkerIt.value()(output); + ret = ret && checkerIt != g_options.checkFiles.end() && checkerIt.value()(output); if (it.value() == QStringLiteral("-")){ fprintf(stdout, "%s", output.constData()); fflush(stdout); -- cgit v1.2.3 From 5b2dfbc649a7c20a93223cd4c274a4b0fe847df8 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Fri, 24 May 2019 21:20:37 +0200 Subject: Long live QSize(F)::grownBy/shrunkBy() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These functions tighten the integration of QMargins(F) with the rest of the geometry classes by providing a way to apply margins to sizes (and later, rects). Apply them in a few obvious cases across QtWidgets. [ChangeLog][QtCore][QSize/QSizeF] Added grownBy(QMargin(F))/shrunkBy(QMargin(F)). Change-Id: I8a549436824cdb7fb6125a8cde89d5bf02826934 Reviewed-by: MÃ¥rten Nordheim Reviewed-by: Shawn Rutledge Reviewed-by: Edward Welbourne --- src/corelib/tools/qsize.cpp | 18 +++++++++++ src/corelib/tools/qsize.h | 11 +++++++ src/widgets/widgets/qdockarealayout.cpp | 21 ++++-------- src/widgets/widgets/qdockwidget.cpp | 7 ++-- tests/auto/corelib/tools/qsize/tst_qsize.cpp | 44 ++++++++++++++++++++++++++ tests/auto/corelib/tools/qsizef/tst_qsizef.cpp | 44 ++++++++++++++++++++++++++ 6 files changed, 126 insertions(+), 19 deletions(-) diff --git a/src/corelib/tools/qsize.cpp b/src/corelib/tools/qsize.cpp index fe508ad459..2cbaae117d 100644 --- a/src/corelib/tools/qsize.cpp +++ b/src/corelib/tools/qsize.cpp @@ -390,7 +390,25 @@ QSize QSize::scaled(const QSize &s, Qt::AspectRatioMode mode) const noexcept \sa expandedTo(), scale() */ +/*! + \fn QSize QSize::grownBy(QMargins margins) const + \fn QSizeF QSizeF::grownBy(QMarginsF margins) const + \since 5.14 + + Returns the size that results from growing this size by \a margins. + + \sa shrunkBy() +*/ +/*! + \fn QSize QSize::shrunkBy(QMargins margins) const + \fn QSizeF QSizeF::shrunkBy(QMarginsF margins) const + \since 5.14 + + Returns the size that results from shrinking this size by \a margins. + + \sa grownBy() +*/ /***************************************************************************** QSize stream functions diff --git a/src/corelib/tools/qsize.h b/src/corelib/tools/qsize.h index 4114609856..06de1cd63f 100644 --- a/src/corelib/tools/qsize.h +++ b/src/corelib/tools/qsize.h @@ -41,6 +41,7 @@ #define QSIZE_H #include +#include #if defined(Q_OS_DARWIN) || defined(Q_QDOC) struct CGSize; @@ -74,6 +75,11 @@ public: Q_REQUIRED_RESULT Q_DECL_CONSTEXPR inline QSize expandedTo(const QSize &) const noexcept; Q_REQUIRED_RESULT Q_DECL_CONSTEXPR inline QSize boundedTo(const QSize &) const noexcept; + Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QSize grownBy(QMargins m) const noexcept + { return {width() + m.left() + m.right(), height() + m.top() + m.bottom()}; } + Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QSize shrunkBy(QMargins m) const noexcept + { return {width() - m.left() - m.right(), height() - m.top() - m.bottom()}; } + Q_DECL_RELAXED_CONSTEXPR inline int &rwidth() noexcept; Q_DECL_RELAXED_CONSTEXPR inline int &rheight() noexcept; @@ -238,6 +244,11 @@ public: Q_REQUIRED_RESULT Q_DECL_CONSTEXPR inline QSizeF expandedTo(const QSizeF &) const noexcept; Q_REQUIRED_RESULT Q_DECL_CONSTEXPR inline QSizeF boundedTo(const QSizeF &) const noexcept; + Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QSizeF grownBy(QMarginsF m) const noexcept + { return {width() + m.left() + m.right(), height() + m.top() + m.bottom()}; } + Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QSizeF shrunkBy(QMarginsF m) const noexcept + { return {width() - m.left() - m.right(), height() - m.top() - m.bottom()}; } + Q_DECL_RELAXED_CONSTEXPR inline qreal &rwidth() noexcept; Q_DECL_RELAXED_CONSTEXPR inline qreal &rheight() noexcept; diff --git a/src/widgets/widgets/qdockarealayout.cpp b/src/widgets/widgets/qdockarealayout.cpp index 55ae42db04..8844a85987 100644 --- a/src/widgets/widgets/qdockarealayout.cpp +++ b/src/widgets/widgets/qdockarealayout.cpp @@ -138,11 +138,8 @@ bool QDockAreaLayoutItem::skip() const QSize QDockAreaLayoutItem::minimumSize() const { - if (widgetItem != 0) { - int left, top, right, bottom; - widgetItem->widget()->getContentsMargins(&left, &top, &right, &bottom); - return widgetItem->minimumSize() + QSize(left+right, top+bottom); - } + if (widgetItem) + return widgetItem->minimumSize().grownBy(widgetItem->widget()->contentsMargins()); if (subinfo != 0) return subinfo->minimumSize(); return QSize(0, 0); @@ -150,11 +147,8 @@ QSize QDockAreaLayoutItem::minimumSize() const QSize QDockAreaLayoutItem::maximumSize() const { - if (widgetItem != 0) { - int left, top, right, bottom; - widgetItem->widget()->getContentsMargins(&left, &top, &right, &bottom); - return widgetItem->maximumSize()+ QSize(left+right, top+bottom); - } + if (widgetItem) + return widgetItem->maximumSize().grownBy(widgetItem->widget()->contentsMargins()); if (subinfo != 0) return subinfo->maximumSize(); return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); @@ -180,11 +174,8 @@ QSize QDockAreaLayoutItem::sizeHint() const { if (placeHolderItem != 0) return QSize(0, 0); - if (widgetItem != 0) { - int left, top, right, bottom; - widgetItem->widget()->getContentsMargins(&left, &top, &right, &bottom); - return widgetItem->sizeHint() + QSize(left+right, top+bottom); - } + if (widgetItem) + return widgetItem->sizeHint().grownBy(widgetItem->widget()->contentsMargins()); if (subinfo != 0) return subinfo->sizeHint(); return QSize(-1, -1); diff --git a/src/widgets/widgets/qdockwidget.cpp b/src/widgets/widgets/qdockwidget.cpp index 28a7cee2a0..a7010f9260 100644 --- a/src/widgets/widgets/qdockwidget.cpp +++ b/src/widgets/widgets/qdockwidget.cpp @@ -381,11 +381,10 @@ QSize QDockWidgetLayout::sizeFromContent(const QSize &content, bool floating) co if (content.height() < 0) result.setHeight(-1); - int left, top, right, bottom; - w->getContentsMargins(&left, &top, &right, &bottom); + const QMargins margins = w->contentsMargins(); //we need to subtract the contents margin (it will be added by the caller) - QSize min = w->minimumSize() - QSize(left + right, top + bottom); - QSize max = w->maximumSize() - QSize(left + right, top + bottom); + QSize min = w->minimumSize().shrunkBy(margins); + QSize max = w->maximumSize().shrunkBy(margins); /* A floating dockwidget will automatically get its minimumSize set to the layout's minimum size + deco. We're *not* interested in this, we only take minimumSize() diff --git a/tests/auto/corelib/tools/qsize/tst_qsize.cpp b/tests/auto/corelib/tools/qsize/tst_qsize.cpp index 385ff18ce5..6824bad9c8 100644 --- a/tests/auto/corelib/tools/qsize/tst_qsize.cpp +++ b/tests/auto/corelib/tools/qsize/tst_qsize.cpp @@ -29,6 +29,7 @@ #include #include +Q_DECLARE_METATYPE(QMargins) class tst_QSize : public QObject { @@ -43,6 +44,9 @@ private slots: void boundedTo_data(); void boundedTo(); + void grownOrShrunkBy_data(); + void grownOrShrunkBy(); + void transpose_data(); void transpose(); }; @@ -186,6 +190,46 @@ void tst_QSize::boundedTo() QCOMPARE( input1.boundedTo(input2), expected); } +void tst_QSize::grownOrShrunkBy_data() +{ + QTest::addColumn("input"); + QTest::addColumn("margins"); + QTest::addColumn("grown"); + QTest::addColumn("shrunk"); + + auto row = [](QSize i, QMargins m, QSize g, QSize s) { + QTest::addRow("{%d,%d}/{%d,%d,%d,%d}", i.width(), i.height(), + m.left(), m.top(), m.right(), m.bottom()) + << i << m << g << s; + }; + + const QSize zero = {0, 0}; + const QSize some = {100, 200}; + const QMargins zeroMargins = {}; + const QMargins negative = {-1, -2, -3, -4}; + const QMargins positive = { 1, 2, 3, 4}; + + row(zero, zeroMargins, zero, zero); + row(zero, negative, {-4, -6}, { 4, 6}); + row(zero, positive, { 4, 6}, {-4, -6}); + row(some, zeroMargins, some, some); + row(some, negative, { 96, 194}, {104, 206}); + row(some, positive, {104, 206}, { 96, 194}); +} + +void tst_QSize::grownOrShrunkBy() +{ + QFETCH(const QSize, input); + QFETCH(const QMargins, margins); + QFETCH(const QSize, grown); + QFETCH(const QSize, shrunk); + + QCOMPARE(input.grownBy(margins), grown); + QCOMPARE(input.shrunkBy(margins), shrunk); + QCOMPARE(grown.shrunkBy(margins), input); + QCOMPARE(shrunk.grownBy(margins), input); +} + void tst_QSize::transpose_data() { QTest::addColumn("input1"); diff --git a/tests/auto/corelib/tools/qsizef/tst_qsizef.cpp b/tests/auto/corelib/tools/qsizef/tst_qsizef.cpp index 42801d63a9..bbffa74a62 100644 --- a/tests/auto/corelib/tools/qsizef/tst_qsizef.cpp +++ b/tests/auto/corelib/tools/qsizef/tst_qsizef.cpp @@ -29,6 +29,7 @@ #include #include +Q_DECLARE_METATYPE(QMarginsF) class tst_QSizeF : public QObject { @@ -45,6 +46,9 @@ private slots: void boundedTo_data(); void boundedTo(); + void grownOrShrunkBy_data(); + void grownOrShrunkBy(); + void transpose_data(); void transpose(); }; @@ -152,6 +156,46 @@ void tst_QSizeF::boundedTo() { QCOMPARE( input1.boundedTo(input2), expected); } +void tst_QSizeF::grownOrShrunkBy_data() +{ + QTest::addColumn("input"); + QTest::addColumn("margins"); + QTest::addColumn("grown"); + QTest::addColumn("shrunk"); + + auto row = [](QSizeF i, QMarginsF m, QSizeF g, QSizeF s) { + QTest::addRow("{%g,%g}/{%g,%g,%g,%g}", i.width(), i.height(), + m.left(), m.top(), m.right(), m.bottom()) + << i << m << g << s; + }; + + const QSizeF zero = {0, 0}; + const QSizeF some = {100, 200}; + const QMarginsF zeroMargins = {}; + const QMarginsF negative = {-1, -2, -3, -4}; + const QMarginsF positive = { 1, 2, 3, 4}; + + row(zero, zeroMargins, zero, zero); + row(zero, negative, {-4, -6}, { 4, 6}); + row(zero, positive, { 4, 6}, {-4, -6}); + row(some, zeroMargins, some, some); + row(some, negative, { 96, 194}, {104, 206}); + row(some, positive, {104, 206}, { 96, 194}); +} + +void tst_QSizeF::grownOrShrunkBy() +{ + QFETCH(const QSizeF, input); + QFETCH(const QMarginsF, margins); + QFETCH(const QSizeF, grown); + QFETCH(const QSizeF, shrunk); + + QCOMPARE(input.grownBy(margins), grown); + QCOMPARE(input.shrunkBy(margins), shrunk); + QCOMPARE(grown.shrunkBy(margins), input); + QCOMPARE(shrunk.grownBy(margins), input); +} + void tst_QSizeF::transpose_data() { QTest::addColumn("input1"); QTest::addColumn("expected"); -- cgit v1.2.3 From d1b099c3e3cfcbf86353b53e205c0ebf84cf5592 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 14 Aug 2019 09:41:18 +0200 Subject: QBezier: replace out parameters by return-by-value in split() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At least QBezier itself is calling the old function with *this aliased to one of the arguments. Consequently, the implementation looks rather ... shuffled, to avoid writing into members that it will read once more later. Fix by returning a std::pair instead. This simplifies the code that doesn't actually pass existing objects in, and avoids aliasing problems cropping up under seemingly innocuous reorderings of statements in the implementation going forward. While I'm usually vehemently against use std::pair or std::tuple in APIs, preferring simple structs with aptly-named members instead, this is one case where the .first and .second actually fit, and pair allows us to use std::tie, which was handy in qbezier.cpp. This patch preserves the body of the function as much as possible. A follow-up patch will clean it up. Change-Id: I017dfee4a0e69a2e171ce21b89ba04654772c33d Reviewed-by: Edward Welbourne Reviewed-by: MÃ¥rten Nordheim --- src/gui/painting/qbezier.cpp | 16 ++++++++-------- src/gui/painting/qbezier_p.h | 11 +++++++---- src/gui/painting/qpainterpath.cpp | 21 +++++++++------------ 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/gui/painting/qbezier.cpp b/src/gui/painting/qbezier.cpp index daf19fffe1..9861fffff3 100644 --- a/src/gui/painting/qbezier.cpp +++ b/src/gui/painting/qbezier.cpp @@ -47,6 +47,8 @@ #include +#include // for std::tie() + QT_BEGIN_NAMESPACE //#define QDEBUG_BEZIER @@ -128,7 +130,7 @@ void QBezier::addToPolygon(QPolygonF *polygon, qreal bezier_flattening_threshold --lvl; } else { // split, second half of the polygon goes lower into the stack - b->split(b+1, b); + std::tie(b[1], b[0]) = b->split(); lvl[1] = --lvl[0]; ++b; ++lvl; @@ -166,7 +168,7 @@ void QBezier::addToPolygon(QDataBuffer &polygon, qreal bezier_flattenin --lvl; } else { // split, second half of the polygon goes lower into the stack - b->split(b+1, b); + std::tie(b[1], b[0]) = b->split(); lvl[1] = --lvl[0]; ++b; ++lvl; @@ -422,7 +424,7 @@ redo: o += 2; --b; } else { - b->split(b+1, b); + std::tie(b[1], b[0]) = b->split(); ++b; } } @@ -464,8 +466,6 @@ qreal QBezier::length(qreal error) const void QBezier::addIfClose(qreal *length, qreal error) const { - QBezier left, right; /* bez poly splits */ - qreal len = qreal(0.0); /* arc length */ qreal chord; /* chord length */ @@ -476,9 +476,9 @@ void QBezier::addIfClose(qreal *length, qreal error) const chord = QLineF(QPointF(x1, y1),QPointF(x4, y4)).length(); if((len-chord) > error) { - split(&left, &right); /* split in two */ - left.addIfClose(length, error); /* try left side */ - right.addIfClose(length, error); /* try right side */ + const auto halves = split(); /* split in two */ + halves.first.addIfClose(length, error); /* try left side */ + halves.second.addIfClose(length, error); /* try right side */ return; } diff --git a/src/gui/painting/qbezier_p.h b/src/gui/painting/qbezier_p.h index f88e3b35b3..02b29c5ba7 100644 --- a/src/gui/painting/qbezier_p.h +++ b/src/gui/painting/qbezier_p.h @@ -107,7 +107,7 @@ public: inline QLineF endTangent() const; inline void parameterSplitLeft(qreal t, QBezier *left); - inline void split(QBezier *firstHalf, QBezier *secondHalf) const; + inline std::pair split() const; int shifted(QBezier *curveSegments, int maxSegmets, qreal offset, float threshold) const; @@ -223,10 +223,11 @@ inline QPointF QBezier::secondDerivedAt(qreal t) const a * y1 + b * y2 + c * y3 + d * y4); } -inline void QBezier::split(QBezier *firstHalf, QBezier *secondHalf) const +std::pair QBezier::split() const { - Q_ASSERT(firstHalf); - Q_ASSERT(secondHalf); + std::pair r; + auto firstHalf = &r.first; + auto secondHalf = &r.second; qreal c = (x2 + x3)*.5; firstHalf->x2 = (x1 + x2)*.5; @@ -245,6 +246,8 @@ inline void QBezier::split(QBezier *firstHalf, QBezier *secondHalf) const firstHalf->y3 = (firstHalf->y2 + c)*.5; secondHalf->y2 = (secondHalf->y3 + c)*.5; firstHalf->y4 = secondHalf->y1 = (firstHalf->y3 + secondHalf->y2)*.5; + + return r; } inline void QBezier::parameterSplitLeft(qreal t, QBezier *left) diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp index b1d1f30800..1fb37ece56 100644 --- a/src/gui/painting/qpainterpath.cpp +++ b/src/gui/painting/qpainterpath.cpp @@ -1855,10 +1855,9 @@ static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt, } // split curve and try again... - QBezier first_half, second_half; - bezier.split(&first_half, &second_half); - qt_painterpath_isect_curve(first_half, pt, winding, depth + 1); - qt_painterpath_isect_curve(second_half, pt, winding, depth + 1); + const auto halves = bezier.split(); + qt_painterpath_isect_curve(halves.first, pt, winding, depth + 1); + qt_painterpath_isect_curve(halves.second, pt, winding, depth + 1); } } @@ -2013,10 +2012,9 @@ static bool qt_isect_curve_horizontal(const QBezier &bezier, qreal y, qreal x1, if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound)) return true; - QBezier first_half, second_half; - bezier.split(&first_half, &second_half); - if (qt_isect_curve_horizontal(first_half, y, x1, x2, depth + 1) - || qt_isect_curve_horizontal(second_half, y, x1, x2, depth + 1)) + const auto halves = bezier.split(); + if (qt_isect_curve_horizontal(halves.first, y, x1, x2, depth + 1) + || qt_isect_curve_horizontal(halves.second, y, x1, x2, depth + 1)) return true; } return false; @@ -2032,10 +2030,9 @@ static bool qt_isect_curve_vertical(const QBezier &bezier, qreal x, qreal y1, qr if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound)) return true; - QBezier first_half, second_half; - bezier.split(&first_half, &second_half); - if (qt_isect_curve_vertical(first_half, x, y1, y2, depth + 1) - || qt_isect_curve_vertical(second_half, x, y1, y2, depth + 1)) + const auto halves = bezier.split(); + if (qt_isect_curve_vertical(halves.first, x, y1, y2, depth + 1) + || qt_isect_curve_vertical(halves.second, x, y1, y2, depth + 1)) return true; } return false; -- cgit v1.2.3 From a52a3b2aa43870e9b9b76cf628e5e666d7ecc457 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Mon, 5 Aug 2019 22:54:33 +0200 Subject: Micro-optimize QAbstractItemModel::setItemData If b becomes false, we won't call setData ever again. Just bail out the loop early and return in that case. Change-Id: I4b0ed7e21546d686bc3f785209a314a8bed08471 Reviewed-by: Volker Hilsheimer Reviewed-by: Marc Mutz --- src/corelib/itemmodels/qabstractitemmodel.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp index c5fb5b9fc5..6e97c2fd39 100644 --- a/src/corelib/itemmodels/qabstractitemmodel.cpp +++ b/src/corelib/itemmodels/qabstractitemmodel.cpp @@ -1898,10 +1898,17 @@ bool QAbstractItemModel::clearItemData(const QModelIndex &index) */ bool QAbstractItemModel::setItemData(const QModelIndex &index, const QMap &roles) { - bool b = true; - for (QMap::ConstIterator it = roles.begin(); it != roles.end(); ++it) - b = b && setData(index, it.value(), it.key()); - return b; + // ### Qt 6: Consider change the semantics of this function, + // or deprecating/removing it altogether. + // + // For instance, it should try setting *all* the data + // in \a roles, and not bail out at the first setData that returns + // false. It should also have a transactional approach. + for (auto it = roles.begin(), e = roles.end(); it != e; ++it) { + if (!setData(index, it.value(), it.key())) + return false; + } + return true; } /*! -- cgit v1.2.3 From a4d19654edec88b5ca0a2516c1b2038ad309ca6d Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 15 Aug 2019 10:59:23 +0200 Subject: Simplify QBezier::split() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that result objects can't alias source ones anymore, the order of writes no longer matters, and we can clean this function up. The pattern of the algorithm now becomes visible. Before, it was just drowing in noise. Change-Id: I36c55ce09d6e13a994c7eda17d96cfe960e7fb95 Reviewed-by: MÃ¥rten Nordheim Reviewed-by: Eirik Aavitsland --- src/gui/painting/qbezier_p.h | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/src/gui/painting/qbezier_p.h b/src/gui/painting/qbezier_p.h index 02b29c5ba7..1c49f82416 100644 --- a/src/gui/painting/qbezier_p.h +++ b/src/gui/painting/qbezier_p.h @@ -225,29 +225,19 @@ inline QPointF QBezier::secondDerivedAt(qreal t) const std::pair QBezier::split() const { - std::pair r; - auto firstHalf = &r.first; - auto secondHalf = &r.second; - - qreal c = (x2 + x3)*.5; - firstHalf->x2 = (x1 + x2)*.5; - secondHalf->x3 = (x3 + x4)*.5; - firstHalf->x1 = x1; - secondHalf->x4 = x4; - firstHalf->x3 = (firstHalf->x2 + c)*.5; - secondHalf->x2 = (secondHalf->x3 + c)*.5; - firstHalf->x4 = secondHalf->x1 = (firstHalf->x3 + secondHalf->x2)*.5; - - c = (y2 + y3)/2; - firstHalf->y2 = (y1 + y2)*.5; - secondHalf->y3 = (y3 + y4)*.5; - firstHalf->y1 = y1; - secondHalf->y4 = y4; - firstHalf->y3 = (firstHalf->y2 + c)*.5; - secondHalf->y2 = (secondHalf->y3 + c)*.5; - firstHalf->y4 = secondHalf->y1 = (firstHalf->y3 + secondHalf->y2)*.5; - - return r; + const auto mid = [](QPointF lhs, QPointF rhs) { return (lhs + rhs) * .5; }; + + const QPointF mid_12 = mid(pt1(), pt2()); + const QPointF mid_23 = mid(pt2(), pt3()); + const QPointF mid_34 = mid(pt3(), pt4()); + const QPointF mid_12_23 = mid(mid_12, mid_23); + const QPointF mid_23_34 = mid(mid_23, mid_34); + const QPointF mid_12_23__23_34 = mid(mid_12_23, mid_23_34); + + return { + fromPoints(pt1(), mid_12, mid_12_23, mid_12_23__23_34), + fromPoints(mid_12_23__23_34, mid_23_34, mid_34, pt4()), + }; } inline void QBezier::parameterSplitLeft(qreal t, QBezier *left) -- cgit v1.2.3 From 9b14950ff600a4ce5a8698b67ab38907c50417f1 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Tue, 9 Jul 2019 10:34:31 +0300 Subject: Android: Update clang mkspecs Follow Google's BuildSystemMaintainers doc to simplify (a lot) the clang support It is needed to support future NDK releases painlessly. Also remove old workarounds. [ChangeLog][Android] Android depends on NDK r20+ Change-Id: Ib4c07fc71e0f5a264d804b0b3baa18ff79d07630 Reviewed-by: Eskil Abrahamsen Blomfeldt --- mkspecs/android-clang/qmake.conf | 36 ++++++++++++++--------------------- mkspecs/android-g++/qmake.conf | 5 +++++ mkspecs/common/android-base-head.conf | 1 - mkspecs/common/android-base-tail.conf | 16 ++++------------ src/corelib/text/qstring.h | 9 --------- src/gui/text/qcssparser.cpp | 4 ---- 6 files changed, 23 insertions(+), 48 deletions(-) diff --git a/mkspecs/android-clang/qmake.conf b/mkspecs/android-clang/qmake.conf index 8569c08348..84ad884710 100644 --- a/mkspecs/android-clang/qmake.conf +++ b/mkspecs/android-clang/qmake.conf @@ -14,37 +14,29 @@ NDK_LLVM_PATH = $$NDK_ROOT/toolchains/llvm/prebuilt/$$NDK_HOST QMAKE_CC = $$NDK_LLVM_PATH/bin/clang QMAKE_CXX = $$NDK_LLVM_PATH/bin/clang++ +# Follow https://android.googlesource.com/platform/ndk/+/ndk-release-r20/docs/BuildSystemMaintainers.md + equals(ANDROID_TARGET_ARCH, armeabi-v7a): \ - QMAKE_CFLAGS += -target armv7-none-linux-androideabi -else: equals(ANDROID_TARGET_ARCH, armeabi): \ - QMAKE_CFLAGS += -target armv5te-none-linux-androideabi + QMAKE_CFLAGS = -target armv7a-linux-androideabi$$replace(ANDROID_PLATFORM, "android-", "") else: equals(ANDROID_TARGET_ARCH, arm64-v8a): \ - QMAKE_CFLAGS += -target aarch64-none-linux-android + QMAKE_CFLAGS = -target aarch64-linux-android$$replace(ANDROID_PLATFORM, "android-", "") else: equals(ANDROID_TARGET_ARCH, x86): \ - QMAKE_CFLAGS += -target i686-none-linux-android -mstackrealign + QMAKE_CFLAGS = -target i686-linux-android$$replace(ANDROID_PLATFORM, "android-", "") -mstackrealign else: equals(ANDROID_TARGET_ARCH, x86_64): \ - QMAKE_CFLAGS += -target x86_64-none-linux-android - -QMAKE_CFLAGS += -gcc-toolchain $$NDK_TOOLCHAIN_PATH -fno-limit-debug-info - -QMAKE_LINK = $$QMAKE_CXX $$QMAKE_CFLAGS -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a -nostdlib++ -equals(ANDROID_TARGET_ARCH, armeabi-v7a): QMAKE_LINK += -Wl,--exclude-libs,libunwind.a + QMAKE_CFLAGS = -target x86_64-linux-android$$replace(ANDROID_PLATFORM, "android-", "") -QMAKE_CFLAGS += -DANDROID_HAS_WSTRING --sysroot=$$NDK_ROOT/sysroot \ - -isystem $$NDK_ROOT/sysroot/usr/include/$$NDK_TOOLS_PREFIX \ - -isystem $$NDK_ROOT/sources/cxx-stl/llvm-libc++/include \ - -isystem $$NDK_ROOT/sources/android/support/include \ - -isystem $$NDK_ROOT/sources/cxx-stl/llvm-libc++abi/include +QMAKE_CFLAGS += -fno-limit-debug-info -ANDROID_SOURCES_CXX_STL_LIBDIR = $$NDK_ROOT/sources/cxx-stl/llvm-libc++/libs/$$ANDROID_TARGET_ARCH +QMAKE_LINK = $$QMAKE_CXX $$QMAKE_CFLAGS -ANDROID_STDCPP_PATH = $$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++_shared.so +ANDROID_STDCPP_PATH = $$NDK_LLVM_PATH/sysroot/usr/lib/$$NDK_TOOLS_PREFIX/libc++_shared.so ANDROID_USE_LLVM = true -exists($$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++.so): \ - ANDROID_CXX_STL_LIBS = -lc++ -else: \ - ANDROID_CXX_STL_LIBS = $$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++.so.$$replace(ANDROID_PLATFORM, "android-", "") +QMAKE_CFLAGS_OPTIMIZE_SIZE = -Oz +QMAKE_LIBDIR_POST = +QMAKE_LFLAGS = +QMAKE_LIBS_PRIVATE = +ANDROID_CXX_STL_LIBS = include(../common/android-base-tail.conf) diff --git a/mkspecs/android-g++/qmake.conf b/mkspecs/android-g++/qmake.conf index 0cb3558f96..451e12bc75 100644 --- a/mkspecs/android-g++/qmake.conf +++ b/mkspecs/android-g++/qmake.conf @@ -12,6 +12,7 @@ include(../common/android-base-head.conf) QMAKE_CC = $${CROSS_COMPILE}gcc QMAKE_CXX = $${CROSS_COMPILE}g++ QMAKE_LINK = $$QMAKE_CXX +QMAKE_CFLAGS = -D__ANDROID_API__=$$replace(ANDROID_PLATFORM, "android-", "") ANDROID_SOURCES_CXX_STL_LIBDIR = $$NDK_ROOT/sources/cxx-stl/gnu-libstdc++/$$NDK_TOOLCHAIN_VERSION/libs/$$ANDROID_TARGET_ARCH ANDROID_STDCPP_PATH = $$ANDROID_SOURCES_CXX_STL_LIBDIR/libgnustl_shared.so @@ -32,4 +33,8 @@ else: \ LIBGCC_PATH_FULL = $$system("$$QMAKE_CXX -print-libgcc-file-name") ANDROID_SOURCES_CXX_STL_LIBDIR += $$dirname(LIBGCC_PATH_FULL) +QMAKE_LIBDIR_POST = $$ANDROID_SOURCES_CXX_STL_LIBDIR +QMAKE_LFLAGS = --sysroot=$$ANDROID_PLATFORM_ROOT_PATH +equals(ANDROID_TARGET_ARCH, x86_64) QMAKE_LFLAGS += -L$$ANDROID_PLATFORM_ROOT_PATH/usr/lib64 + include(../common/android-base-tail.conf) diff --git a/mkspecs/common/android-base-head.conf b/mkspecs/common/android-base-head.conf index ba90ad5f17..7335b7f4cb 100644 --- a/mkspecs/common/android-base-head.conf +++ b/mkspecs/common/android-base-head.conf @@ -58,7 +58,6 @@ isEmpty(ANDROID_SDK_BUILD_TOOLS_REVISION) { } CONFIG += $$ANDROID_PLATFORM -QMAKE_CFLAGS = -D__ANDROID_API__=$$replace(ANDROID_PLATFORM, "android-", "") ANDROID_PLATFORM_ROOT_PATH = $$NDK_ROOT/platforms/$$ANDROID_PLATFORM/arch-$$ANDROID_ARCHITECTURE/ diff --git a/mkspecs/common/android-base-tail.conf b/mkspecs/common/android-base-tail.conf index edc255d08e..c970379f28 100644 --- a/mkspecs/common/android-base-tail.conf +++ b/mkspecs/common/android-base-tail.conf @@ -6,22 +6,17 @@ isEmpty(DEFAULT_ANDROID_NDK_ROOT): return() QMAKE_CFLAGS += -fstack-protector-strong -DANDROID equals(ANDROID_TARGET_ARCH, armeabi-v7a): \ - QMAKE_CFLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=vfp -fno-builtin-memmove + QMAKE_CFLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=vfp else: equals(ANDROID_TARGET_ARCH, armeabi): \ - QMAKE_CFLAGS += -march=armv5te -mtune=xscale -msoft-float -fno-builtin-memmove -# -fno-builtin-memmove is used to workaround https://code.google.com/p/android/issues/detail?id=81692 + QMAKE_CFLAGS += -march=armv5te -mtune=xscale -msoft-float QMAKE_CFLAGS_WARN_ON = -Wall -W QMAKE_CFLAGS_WARN_OFF = equals(ANDROID_TARGET_ARCH, armeabi-v7a) | equals(ANDROID_TARGET_ARCH, armeabi) { CONFIG += optimize_size QMAKE_CFLAGS_DEBUG = -g -marm -O0 - equals(ANDROID_TARGET_ARCH, armeabi):if(equals(NDK_TOOLCHAIN_VERSION, 4.8)|equals(NDK_TOOLCHAIN_VERSION, 4.9)) { - DEFINES += QT_OS_ANDROID_GCC_48_WORKAROUND - } else { - QMAKE_CFLAGS_RELEASE += -mthumb - QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -mthumb - } + QMAKE_CFLAGS_RELEASE += -mthumb + QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -mthumb } QMAKE_CFLAGS_SHLIB = -fPIC @@ -61,15 +56,12 @@ QMAKE_STRIP = QMAKE_RANLIB = $${CROSS_COMPILE}ranlib QMAKE_INCDIR_POST = -QMAKE_LIBDIR_POST = $$ANDROID_SOURCES_CXX_STL_LIBDIR QMAKE_INCDIR_X11 = QMAKE_LIBDIR_X11 = QMAKE_INCDIR_OPENGL = QMAKE_LIBDIR_OPENGL = QMAKE_LINK_SHLIB = $$QMAKE_LINK -QMAKE_LFLAGS = --sysroot=$$ANDROID_PLATFORM_ROOT_PATH -equals(ANDROID_TARGET_ARCH, x86_64) QMAKE_LFLAGS += -L$$ANDROID_PLATFORM_ROOT_PATH/usr/lib64 QMAKE_LFLAGS_APP = -Wl,--no-undefined -Wl,-z,noexecstack -shared QMAKE_LFLAGS_SHLIB = -Wl,--no-undefined -Wl,-z,noexecstack -shared QMAKE_LFLAGS_PLUGIN = $$QMAKE_LFLAGS_SHLIB diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index 88286b902a..7b1351666d 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -57,15 +57,6 @@ #include #include -#if defined(Q_OS_ANDROID) && !defined(ANDROID_HAS_WSTRING) -// std::wstring is disabled on android's glibc, as bionic lacks certain features -// that libstdc++ checks for (like mbcslen). -namespace std -{ - typedef basic_string wstring; -} -#endif - #include #ifdef truncate diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp index 0b2dedf5dc..ce7c7610c1 100644 --- a/src/gui/text/qcssparser.cpp +++ b/src/gui/text/qcssparser.cpp @@ -612,11 +612,7 @@ bool ValueExtractor::extractBorder(int *borders, QBrush *colors, BorderStyle *st case BorderRightStyle: styles[RightEdge] = decl.styleValue(); break; case BorderStyles: decl.styleValues(styles); break; -#ifndef QT_OS_ANDROID_GCC_48_WORKAROUND case BorderTopLeftRadius: radii[0] = sizeValue(decl); break; -#else - case BorderTopLeftRadius: new(radii)QSize(sizeValue(decl)); break; -#endif case BorderTopRightRadius: radii[1] = sizeValue(decl); break; case BorderBottomLeftRadius: radii[2] = sizeValue(decl); break; case BorderBottomRightRadius: radii[3] = sizeValue(decl); break; -- cgit v1.2.3 From d55712153a357cc5cc975bf599470619b7c77faa Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Wed, 21 Aug 2019 18:53:41 +0300 Subject: tst_NoQtEventLoop: destroy hidden windows Otherwise, we get a warning: QWARN : tst_NoQtEventLoop::consumeSocketEvents() QWindowsContext::windowsProc: No Qt Window found for event 0x2a3 (WM_MOUSELEAVE), hwnd=0x0x9b80646. in the event loop which is running by another test. So, add missing 'delete' call. Change-Id: Ib9b24155bdd6e78062a5234c317c9f878906e413 Reviewed-by: Friedemann Kleint --- tests/auto/gui/kernel/noqteventloop/tst_noqteventloop.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/auto/gui/kernel/noqteventloop/tst_noqteventloop.cpp b/tests/auto/gui/kernel/noqteventloop/tst_noqteventloop.cpp index 4fca9a07fc..19c5c8a4a0 100644 --- a/tests/auto/gui/kernel/noqteventloop/tst_noqteventloop.cpp +++ b/tests/auto/gui/kernel/noqteventloop/tst_noqteventloop.cpp @@ -258,8 +258,8 @@ void tst_NoQtEventLoop::consumeMouseEvents() ::SetWindowPos(mainWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - Window *childWindow = new Window; - childWindow->setParent(QWindow::fromWinId((WId)mainWnd)); + QWindow *mainWindow = QWindow::fromWinId(reinterpret_cast(mainWnd)); + Window *childWindow = new Window(mainWindow); childWindow->setGeometry(margin, topVerticalMargin, width - 2 * margin, height - margin - topVerticalMargin); childWindow->show(); @@ -276,6 +276,7 @@ void tst_NoQtEventLoop::consumeMouseEvents() if (g_exit) break; } + delete mainWindow; QCOMPARE(testThread->passed(), true); -- cgit v1.2.3 From 8d302aea33d54d7930fc700ab44a55e058d7bfcc Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 20 Aug 2019 12:09:42 +0200 Subject: HTTP/2: use a non-default MAX_FRAME_SIZE And send it in our 'SETTINGS' frame. Add an auto-test for this and (as a bonus) - fix a bug accidentally introduced by the previous change. Task-number: QTBUG-77412 Change-Id: I4277ff47e8d8d3b6b8666fbcd7dc73c827f349c0 Reviewed-by: Volker Hilsheimer --- src/network/access/http2/http2protocol.cpp | 10 ++-- tests/auto/network/access/http2/http2srv.cpp | 6 ++- tests/auto/network/access/http2/http2srv.h | 1 + tests/auto/network/access/http2/tst_http2.cpp | 70 +++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 4 deletions(-) diff --git a/src/network/access/http2/http2protocol.cpp b/src/network/access/http2/http2protocol.cpp index 0290f9ac00..31da6fd616 100644 --- a/src/network/access/http2/http2protocol.cpp +++ b/src/network/access/http2/http2protocol.cpp @@ -75,9 +75,13 @@ Frame configurationToSettingsFrame(const QHttp2Configuration &config) builder.append(Settings::INITIAL_WINDOW_SIZE_ID); builder.append(config.streamReceiveWindowSize()); - // TODO: Max frame size; in future, if the need - // is proven, we can also set decoding table size - // and header list size. For now, defaults suffice. + if (config.maxFrameSize() != minPayloadLimit) { + builder.append(Settings::MAX_FRAME_SIZE_ID); + builder.append(config.maxFrameSize()); + } + // TODO: In future, if the need is proven, we can + // also send decoding table size and header list size. + // For now, defaults suffice. return builder.outboundFrame(); } diff --git a/tests/auto/network/access/http2/http2srv.cpp b/tests/auto/network/access/http2/http2srv.cpp index 1ddb6aa77d..a8eebf5a24 100644 --- a/tests/auto/network/access/http2/http2srv.cpp +++ b/tests/auto/network/access/http2/http2srv.cpp @@ -218,7 +218,7 @@ void Http2Server::sendDATA(quint32 streamID, quint32 windowSize) quint32 bytesToSend = std::min(windowSize, responseBody.size() - offset); quint32 bytesSent = 0; - const quint32 frameSizeLimit(clientSetting(Settings::MAX_FRAME_SIZE_ID, Http2::maxPayloadSize)); + const quint32 frameSizeLimit(clientSetting(Settings::MAX_FRAME_SIZE_ID, Http2::minPayloadLimit)); const uchar *src = reinterpret_cast(responseBody.constData() + offset); const bool last = offset + bytesToSend == quint32(responseBody.size()); @@ -236,6 +236,10 @@ void Http2Server::sendDATA(quint32 streamID, quint32 windowSize) src += chunkSize; bytesToSend -= chunkSize; bytesSent += chunkSize; + if (frameSizeLimit != Http2::minPayloadLimit) { + // Our test is probably interested in how many DATA frames were sent. + emit sendingData(); + } } if (interrupted.loadAcquire()) diff --git a/tests/auto/network/access/http2/http2srv.h b/tests/auto/network/access/http2/http2srv.h index 9cb846b0b3..3105684d59 100644 --- a/tests/auto/network/access/http2/http2srv.h +++ b/tests/auto/network/access/http2/http2srv.h @@ -128,6 +128,7 @@ Q_SIGNALS: void receivedRequest(quint32 streamID); void receivedData(quint32 streamID); void windowUpdate(quint32 streamID); + void sendingData(); private slots: void connectionEstablished(); diff --git a/tests/auto/network/access/http2/tst_http2.cpp b/tests/auto/network/access/http2/tst_http2.cpp index 6a0dc6db02..e24a06bc34 100644 --- a/tests/auto/network/access/http2/tst_http2.cpp +++ b/tests/auto/network/access/http2/tst_http2.cpp @@ -82,6 +82,8 @@ RawSettings qt_H2ConfigurationToSettings(const QHttp2Configuration &config = qt_ RawSettings settings; settings[Http2::Settings::ENABLE_PUSH_ID] = config.serverPushEnabled(); settings[Http2::Settings::INITIAL_WINDOW_SIZE_ID] = config.streamReceiveWindowSize(); + if (config.maxFrameSize() != Http2::minPayloadLimit) + settings[Http2::Settings::MAX_FRAME_SIZE_ID] = config.maxFrameSize(); return settings; } @@ -107,6 +109,7 @@ private slots: void earlyResponse(); void connectToHost_data(); void connectToHost(); + void maxFrameSize(); protected slots: // Slots to listen to our in-process server: @@ -696,6 +699,73 @@ void tst_Http2::connectToHost() QVERIFY(reply->isFinished()); } +void tst_Http2::maxFrameSize() +{ +#if !QT_CONFIG(ssl) + QSKIP("TLS support is needed for this test"); +#endif // QT_CONFIG(ssl) + + // Here we test we send 'MAX_FRAME_SIZE' setting in our + // 'SETTINGS'. If done properly, our server will not chunk + // the payload into several DATA frames. + +#if QT_CONFIG(securetransport) + // Normally on macOS we use plain text only for SecureTransport + // does not support ALPN on the server side. With 'direct encrytped' + // we have to use TLS sockets (== private key) and thus suppress a + // keychain UI asking for permission to use a private key. + // Our CI has this, but somebody testing locally - will have a problem. + qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", QByteArray("1")); + auto envRollback = qScopeGuard([](){ + qunsetenv("QT_SSL_USE_TEMPORARY_KEYCHAIN"); + }); +#endif // QT_CONFIG(securetransport) + + auto connectionType = H2Type::h2Alpn; + auto attribute = QNetworkRequest::HTTP2AllowedAttribute; + if (clearTextHTTP2) { + connectionType = H2Type::h2Direct; + attribute = QNetworkRequest::Http2DirectAttribute; + } + + auto h2Config = qt_defaultH2Configuration(); + h2Config.setMaxFrameSize(Http2::minPayloadLimit * 3); + + serverPort = 0; + nRequests = 1; + + ServerPtr srv(newServer(defaultServerSettings, connectionType, + qt_H2ConfigurationToSettings(h2Config))); + srv->setResponseBody(QByteArray(Http2::minPayloadLimit * 2, 'q')); + QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection); + runEventLoop(); + QVERIFY(serverPort != 0); + + const QSignalSpy frameCounter(srv.data(), &Http2Server::sendingData); + auto url = requestUrl(connectionType); + url.setPath(QString("/stream1.html")); + + QNetworkRequest request(url); + request.setAttribute(attribute, QVariant(true)); + request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain")); + request.setHttp2Configuration(h2Config); + + QNetworkReply *reply = manager->get(request); + reply->ignoreSslErrors(); + connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished); + + runEventLoop(); + STOP_ON_FAILURE + + // Normally, with a 16kb limit, our server would split such + // a response into 3 'DATA' frames (16kb + 16kb + 0|END_STREAM). + QCOMPARE(frameCounter.count(), 1); + + QVERIFY(nRequests == 0); + QVERIFY(prefaceOK); + QVERIFY(serverGotSettingsACK); +} + void tst_Http2::serverStarted(quint16 port) { serverPort = port; -- cgit v1.2.3 From 181e5382e741c290d72010da9d6d74908e7b2d8f Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Tue, 20 Aug 2019 10:12:53 +0200 Subject: eglfs/kms: Add drm atomic blend_op property handling Add support for specifying the blend operation used when alpha- blending KMS planes. Only available with atomic modesetting. Set the environment variable QT_QPA_EGLFS_KMS_BLEND_OP to the enum value of the 'blend_op' property. Task-number: QTBUG-75659 Change-Id: If0ef5ba314b88adb530113b608d20fc9c027c5ec Reviewed-by: Laszlo Agocs --- src/platformsupport/kmsconvenience/qkmsdevice.cpp | 2 ++ src/platformsupport/kmsconvenience/qkmsdevice_p.h | 1 + .../platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp | 3 +++ 3 files changed, 6 insertions(+) diff --git a/src/platformsupport/kmsconvenience/qkmsdevice.cpp b/src/platformsupport/kmsconvenience/qkmsdevice.cpp index 07ef60c5ff..d9d76c1146 100644 --- a/src/platformsupport/kmsconvenience/qkmsdevice.cpp +++ b/src/platformsupport/kmsconvenience/qkmsdevice.cpp @@ -854,6 +854,8 @@ void QKmsDevice::discoverPlanes() plane.crtcYPropertyId = prop->prop_id; } else if (!strcasecmp(prop->name, "zpos")) { plane.zposPropertyId = prop->prop_id; + } else if (!strcasecmp(prop->name, "blend_op")) { + plane.blendOpPropertyId = prop->prop_id; } }); diff --git a/src/platformsupport/kmsconvenience/qkmsdevice_p.h b/src/platformsupport/kmsconvenience/qkmsdevice_p.h index 403972fbb8..77070c293d 100644 --- a/src/platformsupport/kmsconvenience/qkmsdevice_p.h +++ b/src/platformsupport/kmsconvenience/qkmsdevice_p.h @@ -178,6 +178,7 @@ struct QKmsPlane uint32_t crtcwidthPropertyId = 0; uint32_t crtcheightPropertyId = 0; uint32_t zposPropertyId = 0; + uint32_t blendOpPropertyId = 0; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QKmsPlane::Rotations) diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp index 09a10bcc9c..2034632fb3 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp @@ -331,6 +331,9 @@ void QEglFSKmsGbmScreen::flip() static int zpos = qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_ZPOS"); if (zpos) drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->zposPropertyId, zpos); + static uint blendOp = uint(qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_BLEND_OP")); + if (blendOp) + drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->blendOpPropertyId, blendOp); } #endif } else { -- cgit v1.2.3 From f65cfadd041078b80389c178d4f8be055163bdae Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Thu, 22 Aug 2019 10:52:52 +0200 Subject: Improve readability of commands in VS project files The commands are separated by "if errorlevel 1 goto VCEnd" lines to make sure we abort on the first failure. However, we also insert magic comments starting with "Rem" for IncrediBuild. These do not need error checking. Also, the last command does not need error checking. The XML line ending entities are also unneeded. By using proper line endings we ensure that commands appear on separate lines in Visual Studio's property editor. Change-Id: Ifbf7525281e892c820034fafc64b555fff3dc756 Reviewed-by: Miguel Costa --- qmake/generators/win32/msbuild_objectmodel.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/qmake/generators/win32/msbuild_objectmodel.cpp b/qmake/generators/win32/msbuild_objectmodel.cpp index 3116238aa0..0515c7404f 100644 --- a/qmake/generators/win32/msbuild_objectmodel.cpp +++ b/qmake/generators/win32/msbuild_objectmodel.cpp @@ -300,14 +300,17 @@ inline XmlOutput::xml_output valueTagT( const triState v) return valueTag(v == _True ? "true" : "false"); } -static QString vcxCommandSeparator() +static QString commandLinesForOutput(QStringList commands) { // MSBuild puts the contents of the custom commands into a batch file and calls it. // As we want every sub-command to be error-checked (as is done by makefile-based // backends), we insert the checks ourselves, using the undocumented jump target. - static QString cmdSep = - QLatin1String(" if errorlevel 1 goto VCEnd "); - return cmdSep; + static QString errchk = QStringLiteral("if errorlevel 1 goto VCEnd"); + for (int i = commands.count() - 2; i >= 0; --i) { + if (!commands.at(i).startsWith("rem", Qt::CaseInsensitive)) + commands.insert(i + 1, errchk); + } + return commands.join('\n'); } static QString unquote(const QString &value) @@ -1658,7 +1661,7 @@ void VCXProjectWriter::write(XmlOutput &xml, const VCCustomBuildTool &tool) { xml << tag("Command") << attrTag("Condition", condition) - << valueTag(tool.CommandLine.join(vcxCommandSeparator())); + << valueTag(commandLinesForOutput(tool.CommandLine)); } if ( !tool.Description.isEmpty() ) @@ -1712,7 +1715,7 @@ void VCXProjectWriter::write(XmlOutput &xml, const VCEventTool &tool) { xml << tag(tool.EventName) - << tag(_Command) << valueTag(tool.CommandLine.join(vcxCommandSeparator())) + << tag(_Command) << valueTag(commandLinesForOutput(tool.CommandLine)) << tag(_Message) << valueTag(tool.Description) << closetag(tool.EventName); } -- cgit v1.2.3 From 45f681e8183fc876f5943495edb18edf78f29158 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 22 Aug 2019 10:11:26 +0200 Subject: tst_QStyle: Remove unused baseline images (Windows Vista/macOS) The test contained outdated baseline images for 1) Windows Vista: They were only used for OS version Vista and do not match any more. 2) macOS: They were apparently were not in use any more Remove the testing and image comparison code. Task-number: QTBUG-76493 Change-Id: I91cec5113db8d1845b43f97ad2987e63d9f86ac7 Reviewed-by: Christian Ehrlicher --- .../widgets/styles/qstyle/images/mac/button.png | Bin 1785 -> 0 bytes .../widgets/styles/qstyle/images/mac/combobox.png | Bin 1808 -> 0 bytes .../widgets/styles/qstyle/images/mac/lineedit.png | Bin 953 -> 0 bytes .../auto/widgets/styles/qstyle/images/mac/mdi.png | Bin 3092 -> 0 bytes .../auto/widgets/styles/qstyle/images/mac/menu.png | Bin 1139 -> 0 bytes .../styles/qstyle/images/mac/radiobutton.png | Bin 1498 -> 0 bytes .../widgets/styles/qstyle/images/mac/slider.png | Bin 1074 -> 0 bytes .../widgets/styles/qstyle/images/mac/spinbox.png | Bin 1299 -> 0 bytes .../widgets/styles/qstyle/images/vista/button.png | Bin 722 -> 0 bytes .../styles/qstyle/images/vista/combobox.png | Bin 809 -> 0 bytes .../styles/qstyle/images/vista/lineedit.png | Bin 530 -> 0 bytes .../widgets/styles/qstyle/images/vista/menu.png | Bin 646 -> 0 bytes .../styles/qstyle/images/vista/radiobutton.png | Bin 844 -> 0 bytes .../widgets/styles/qstyle/images/vista/slider.png | Bin 575 -> 0 bytes .../widgets/styles/qstyle/images/vista/spinbox.png | Bin 583 -> 0 bytes tests/auto/widgets/styles/qstyle/qstyle.pro | 5 - tests/auto/widgets/styles/qstyle/testdata.qrc | 19 --- tests/auto/widgets/styles/qstyle/tst_qstyle.cpp | 127 --------------------- 18 files changed, 151 deletions(-) delete mode 100644 tests/auto/widgets/styles/qstyle/images/mac/button.png delete mode 100644 tests/auto/widgets/styles/qstyle/images/mac/combobox.png delete mode 100644 tests/auto/widgets/styles/qstyle/images/mac/lineedit.png delete mode 100644 tests/auto/widgets/styles/qstyle/images/mac/mdi.png delete mode 100644 tests/auto/widgets/styles/qstyle/images/mac/menu.png delete mode 100644 tests/auto/widgets/styles/qstyle/images/mac/radiobutton.png delete mode 100644 tests/auto/widgets/styles/qstyle/images/mac/slider.png delete mode 100644 tests/auto/widgets/styles/qstyle/images/mac/spinbox.png delete mode 100644 tests/auto/widgets/styles/qstyle/images/vista/button.png delete mode 100644 tests/auto/widgets/styles/qstyle/images/vista/combobox.png delete mode 100644 tests/auto/widgets/styles/qstyle/images/vista/lineedit.png delete mode 100644 tests/auto/widgets/styles/qstyle/images/vista/menu.png delete mode 100644 tests/auto/widgets/styles/qstyle/images/vista/radiobutton.png delete mode 100644 tests/auto/widgets/styles/qstyle/images/vista/slider.png delete mode 100644 tests/auto/widgets/styles/qstyle/images/vista/spinbox.png delete mode 100644 tests/auto/widgets/styles/qstyle/testdata.qrc diff --git a/tests/auto/widgets/styles/qstyle/images/mac/button.png b/tests/auto/widgets/styles/qstyle/images/mac/button.png deleted file mode 100644 index 7b11325e87..0000000000 Binary files a/tests/auto/widgets/styles/qstyle/images/mac/button.png and /dev/null differ diff --git a/tests/auto/widgets/styles/qstyle/images/mac/combobox.png b/tests/auto/widgets/styles/qstyle/images/mac/combobox.png deleted file mode 100644 index ded0b11f29..0000000000 Binary files a/tests/auto/widgets/styles/qstyle/images/mac/combobox.png and /dev/null differ diff --git a/tests/auto/widgets/styles/qstyle/images/mac/lineedit.png b/tests/auto/widgets/styles/qstyle/images/mac/lineedit.png deleted file mode 100644 index 8d2861b65b..0000000000 Binary files a/tests/auto/widgets/styles/qstyle/images/mac/lineedit.png and /dev/null differ diff --git a/tests/auto/widgets/styles/qstyle/images/mac/mdi.png b/tests/auto/widgets/styles/qstyle/images/mac/mdi.png deleted file mode 100644 index 8c09ae4338..0000000000 Binary files a/tests/auto/widgets/styles/qstyle/images/mac/mdi.png and /dev/null differ diff --git a/tests/auto/widgets/styles/qstyle/images/mac/menu.png b/tests/auto/widgets/styles/qstyle/images/mac/menu.png deleted file mode 100644 index 5dd9111d69..0000000000 Binary files a/tests/auto/widgets/styles/qstyle/images/mac/menu.png and /dev/null differ diff --git a/tests/auto/widgets/styles/qstyle/images/mac/radiobutton.png b/tests/auto/widgets/styles/qstyle/images/mac/radiobutton.png deleted file mode 100644 index 8828e220a2..0000000000 Binary files a/tests/auto/widgets/styles/qstyle/images/mac/radiobutton.png and /dev/null differ diff --git a/tests/auto/widgets/styles/qstyle/images/mac/slider.png b/tests/auto/widgets/styles/qstyle/images/mac/slider.png deleted file mode 100644 index fc65035631..0000000000 Binary files a/tests/auto/widgets/styles/qstyle/images/mac/slider.png and /dev/null differ diff --git a/tests/auto/widgets/styles/qstyle/images/mac/spinbox.png b/tests/auto/widgets/styles/qstyle/images/mac/spinbox.png deleted file mode 100644 index ee88441ecb..0000000000 Binary files a/tests/auto/widgets/styles/qstyle/images/mac/spinbox.png and /dev/null differ diff --git a/tests/auto/widgets/styles/qstyle/images/vista/button.png b/tests/auto/widgets/styles/qstyle/images/vista/button.png deleted file mode 100644 index a6c45276ca..0000000000 Binary files a/tests/auto/widgets/styles/qstyle/images/vista/button.png and /dev/null differ diff --git a/tests/auto/widgets/styles/qstyle/images/vista/combobox.png b/tests/auto/widgets/styles/qstyle/images/vista/combobox.png deleted file mode 100644 index 9b82f64d32..0000000000 Binary files a/tests/auto/widgets/styles/qstyle/images/vista/combobox.png and /dev/null differ diff --git a/tests/auto/widgets/styles/qstyle/images/vista/lineedit.png b/tests/auto/widgets/styles/qstyle/images/vista/lineedit.png deleted file mode 100644 index b2c6ac1ae4..0000000000 Binary files a/tests/auto/widgets/styles/qstyle/images/vista/lineedit.png and /dev/null differ diff --git a/tests/auto/widgets/styles/qstyle/images/vista/menu.png b/tests/auto/widgets/styles/qstyle/images/vista/menu.png deleted file mode 100644 index b114099cc3..0000000000 Binary files a/tests/auto/widgets/styles/qstyle/images/vista/menu.png and /dev/null differ diff --git a/tests/auto/widgets/styles/qstyle/images/vista/radiobutton.png b/tests/auto/widgets/styles/qstyle/images/vista/radiobutton.png deleted file mode 100644 index c8aa7864df..0000000000 Binary files a/tests/auto/widgets/styles/qstyle/images/vista/radiobutton.png and /dev/null differ diff --git a/tests/auto/widgets/styles/qstyle/images/vista/slider.png b/tests/auto/widgets/styles/qstyle/images/vista/slider.png deleted file mode 100644 index 7c156ded9d..0000000000 Binary files a/tests/auto/widgets/styles/qstyle/images/vista/slider.png and /dev/null differ diff --git a/tests/auto/widgets/styles/qstyle/images/vista/spinbox.png b/tests/auto/widgets/styles/qstyle/images/vista/spinbox.png deleted file mode 100644 index b8d0823ab2..0000000000 Binary files a/tests/auto/widgets/styles/qstyle/images/vista/spinbox.png and /dev/null differ diff --git a/tests/auto/widgets/styles/qstyle/qstyle.pro b/tests/auto/widgets/styles/qstyle/qstyle.pro index 9ad0940245..4dc0525c49 100644 --- a/tests/auto/widgets/styles/qstyle/qstyle.pro +++ b/tests/auto/widgets/styles/qstyle/qstyle.pro @@ -2,8 +2,3 @@ CONFIG += testcase TARGET = tst_qstyle QT += widgets testlib testlib-private SOURCES += tst_qstyle.cpp - -android:!android-embedded { - RESOURCES += \ - testdata.qrc -} diff --git a/tests/auto/widgets/styles/qstyle/testdata.qrc b/tests/auto/widgets/styles/qstyle/testdata.qrc deleted file mode 100644 index 29bb46726e..0000000000 --- a/tests/auto/widgets/styles/qstyle/testdata.qrc +++ /dev/null @@ -1,19 +0,0 @@ - - - images/mac/button.png - images/mac/combobox.png - images/mac/lineedit.png - images/mac/mdi.png - images/mac/menu.png - images/mac/radiobutton.png - images/mac/slider.png - images/mac/spinbox.png - images/vista/button.png - images/vista/combobox.png - images/vista/lineedit.png - images/vista/menu.png - images/vista/radiobutton.png - images/vista/slider.png - images/vista/spinbox.png - - diff --git a/tests/auto/widgets/styles/qstyle/tst_qstyle.cpp b/tests/auto/widgets/styles/qstyle/tst_qstyle.cpp index 68e672e16d..ae084310b1 100644 --- a/tests/auto/widgets/styles/qstyle/tst_qstyle.cpp +++ b/tests/auto/widgets/styles/qstyle/tst_qstyle.cpp @@ -73,7 +73,6 @@ public: private: bool testAllFunctions(QStyle *); bool testScrollBarSubControls(); - void testPainting(QStyle *style, const QString &platform); private slots: void drawItemPixmap(); void init(); @@ -333,141 +332,15 @@ void tst_QStyle::testWindowsStyle() delete wstyle; } -void writeImage(const QString &fileName, QImage image) -{ - QImageWriter imageWriter(fileName); - imageWriter.setFormat("png"); - qDebug() << "result " << imageWriter.write(image); -} - -QImage readImage(const QString &fileName) -{ - QImageReader reader(fileName); - return reader.read(); -} - - #if defined(Q_OS_WIN) && !defined(QT_NO_STYLE_WINDOWSVISTA) && !defined(Q_OS_WINRT) void tst_QStyle::testWindowsVistaStyle() { QStyle *vistastyle = QStyleFactory::create("WindowsVista"); QVERIFY(testAllFunctions(vistastyle)); - - if (QOperatingSystemVersion::current().majorVersion() - == QOperatingSystemVersion::WindowsVista.majorVersion() - && QOperatingSystemVersion::current().minorVersion() - == QOperatingSystemVersion::WindowsVista.minorVersion()) - testPainting(vistastyle, "vista"); delete vistastyle; } #endif -void comparePixmap(const QString &filename, const QPixmap &pixmap) -{ - QImage oldFile = readImage(filename); - QPixmap oldPixmap = QPixmap::fromImage(oldFile); - if (!oldFile.isNull()) - QCOMPARE(pixmap, oldPixmap); - else - writeImage(filename, pixmap.toImage()); -} - -void tst_QStyle::testPainting(QStyle *style, const QString &platform) -{ -qDebug("TEST PAINTING"); - //Test Menu - QString fileName = "images/" + platform + "/menu.png"; - QMenu menu; - menu.setStyle(style); - menu.show(); - menu.addAction(new QAction("Test 1", &menu)); - menu.addAction(new QAction("Test 2", &menu)); - QPixmap pixmap = menu.grab(); - comparePixmap(fileName, pixmap); - - //Push button - fileName = "images/" + platform + "/button.png"; - QPushButton button("OK"); - button.setStyle(style); - button.show(); - pixmap = button.grab(); - button.hide(); - comparePixmap(fileName, pixmap); - - //Push button - fileName = "images/" + platform + "/radiobutton.png"; - QRadioButton radiobutton("Check"); - radiobutton.setStyle(style); - radiobutton.show(); - pixmap = radiobutton.grab(); - radiobutton.hide(); - comparePixmap(fileName, pixmap); - - //Combo box - fileName = "images/" + platform + "/combobox.png"; - QComboBox combobox; - combobox.setStyle(style); - combobox.addItem("Test 1"); - combobox.addItem("Test 2"); - combobox.show(); - pixmap = combobox.grab(); - combobox.hide(); - comparePixmap(fileName, pixmap); - - //Spin box - fileName = "images/" + platform + "/spinbox.png"; - QDoubleSpinBox spinbox; - spinbox.setLocale(QLocale(QLocale::English, QLocale::UnitedStates)); - spinbox.setStyle(style); - spinbox.show(); - pixmap = spinbox.grab(); - spinbox.hide(); - comparePixmap(fileName, pixmap); - QLocale::setDefault(QLocale::system()); - - //Slider - fileName = "images/" + platform + "/slider.png"; - QSlider slider; - slider.setStyle(style); - slider.show(); - pixmap = slider.grab(); - slider.hide(); - comparePixmap(fileName, pixmap); - - //Line edit - fileName = "images/" + platform + "/lineedit.png"; - QLineEdit lineedit("Test text"); - lineedit.setStyle(style); - lineedit.show(); - pixmap = lineedit.grab(); - lineedit.hide(); - comparePixmap(fileName, pixmap); - - //MDI - fileName = "images/" + platform + "/mdi.png"; - QMdiArea mdiArea; - mdiArea.addSubWindow(new QWidget(&mdiArea)); - mdiArea.resize(200, 200); - mdiArea.setStyle(style); - mdiArea.show(); - pixmap = mdiArea.grab(); - mdiArea.hide(); - comparePixmap(fileName, pixmap); - - // QToolButton - fileName = "images/" + platform + "/toolbutton.png"; - QToolButton tb; - tb.setToolButtonStyle(Qt::ToolButtonTextUnderIcon); - tb.setText("AaQqPpXx"); - tb.setIcon(style->standardPixmap(QStyle::SP_DirHomeIcon)); - tb.setStyle(style); - tb.show(); - pixmap = tb.grab(); - tb.hide(); - comparePixmap(fileName, pixmap); - -} - #ifdef Q_OS_MAC void tst_QStyle::testMacStyle() { -- cgit v1.2.3 From 3f603906b425152fe41e3b16d91fb25d0b0f0823 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Tue, 20 Aug 2019 10:05:43 +0300 Subject: Android: Set RTLD_NODELETE on API 23+ Change-Id: Ia4b0a6abf862e79b6d7b4c2368f44de0d05a65e9 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/corelib/plugin/qlibrary_unix.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/corelib/plugin/qlibrary_unix.cpp b/src/corelib/plugin/qlibrary_unix.cpp index 84fcc53d52..85ada9197c 100644 --- a/src/corelib/plugin/qlibrary_unix.cpp +++ b/src/corelib/plugin/qlibrary_unix.cpp @@ -52,6 +52,10 @@ # include #endif +#ifdef Q_OS_ANDROID +# include +#endif + QT_BEGIN_NAMESPACE static QString qdlerror() @@ -157,9 +161,12 @@ bool QLibraryPrivate::load_sys() // Do not unload the library during dlclose(). Consequently, the // library's specific static variables are not reinitialized if the // library is reloaded with dlopen() at a later time. -#if defined(RTLD_NODELETE) && !defined(Q_OS_ANDROID) +#if defined(RTLD_NODELETE) if (loadHints & QLibrary::PreventUnloadHint) { - dlFlags |= RTLD_NODELETE; +# ifdef Q_OS_ANDROID // RTLD_NODELETE flag is supported by Android 23+ + if (QtAndroidPrivate::androidSdkVersion() > 22) +# endif + dlFlags |= RTLD_NODELETE; } #endif -- cgit v1.2.3 From a4a11987089b1558b5b50a0d38c3263bb25818d7 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 14 Aug 2019 15:55:31 +0200 Subject: Windows: Fix some widget tests to pass on High DPI screens For tst_QFrame and tst_QOpenGLWidget, force scaling off since they do screen captures which would fail with scaling activated due to different device pixel ratios. For tst_QGraphicsItem and tst_QHeaderView, force scaling on for Windows since some tests otherwise fail due to violation of the minimum size constraints of framed windows on Windows. The tests will then pass regardless of any environment setting of the scaling variables on a developer machine. Change-Id: Iefa4e84b433f7e51dce4e416546a9eda8ee6d0f1 Reviewed-by: Edward Welbourne Reviewed-by: Oliver Wolff --- .../widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp | 11 +++++++++++ tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp | 9 +++++++++ tests/auto/widgets/widgets/qframe/tst_qframe.cpp | 4 ++++ .../auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp | 3 +++ 4 files changed, 27 insertions(+) diff --git a/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp index 7b914512ab..72ea2ae31a 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp @@ -272,6 +272,9 @@ class tst_QGraphicsItem : public QObject { Q_OBJECT +public: + static void initMain(); + private slots: void construction(); void constructionWithParent(); @@ -474,6 +477,14 @@ private: QTouchDevice *m_touchDevice = nullptr; }; +void tst_QGraphicsItem::initMain() +{ +#ifdef Q_OS_WIN + // Ensure minimum size constraints of framed windows on High DPI screens + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif +} + void tst_QGraphicsItem::construction() { for (int i = 0; i < 7; ++i) { diff --git a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp index f247889d55..df02815eb2 100644 --- a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp +++ b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp @@ -106,6 +106,7 @@ class tst_QHeaderView : public QObject public: tst_QHeaderView(); + static void initMain(); private slots: void initTestCase(); @@ -265,6 +266,14 @@ protected: QElapsedTimer timer; }; +void tst_QHeaderView::initMain() +{ +#ifdef Q_OS_WIN + // Ensure minimum size constraints of framed windows on High DPI screens + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif +} + class QtTestModel: public QAbstractTableModel { diff --git a/tests/auto/widgets/widgets/qframe/tst_qframe.cpp b/tests/auto/widgets/widgets/qframe/tst_qframe.cpp index 432f4474c5..05f9cd2e4a 100644 --- a/tests/auto/widgets/widgets/qframe/tst_qframe.cpp +++ b/tests/auto/widgets/widgets/qframe/tst_qframe.cpp @@ -37,6 +37,10 @@ class tst_QFrame : public QObject { Q_OBJECT + +public: + static void initMain() { QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); } + private slots: void testDefaults(); void testInitStyleOption_data(); diff --git a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp index 21c9f41646..76f8ebc804 100644 --- a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp +++ b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp @@ -49,6 +49,9 @@ class tst_QOpenGLWidget : public QObject { Q_OBJECT +public: + static void initMain() { QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); } + private slots: void initTestCase(); void create(); -- cgit v1.2.3 From 5d94aac2bae8bdbf8de7cebeb6a1a17a81685f0a Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 4 Jul 2019 15:17:29 +0200 Subject: Introduce QImage::Format_BGR888 Is pretty common on some architectures so we can avoid swizzling by supporting it. Fixes: QTBUG-45671 Change-Id: Ic7a21b5bfb374bf7496fd2b2b1252c2f1ed47705 Reviewed-by: Eirik Aavitsland --- src/gui/image/qimage.cpp | 15 ++ src/gui/image/qimage.h | 1 + src/gui/image/qimage_conversions.cpp | 222 +++++++++++++++------ src/gui/image/qimage_p.h | 1 + src/gui/image/qimage_ssse3.cpp | 7 +- src/gui/image/qpixmap_win.cpp | 3 +- src/gui/image/qpnghandler.cpp | 2 + src/gui/opengl/qopengltextureuploader.cpp | 18 ++ src/gui/painting/qdrawhelper.cpp | 28 ++- src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp | 2 +- tests/auto/gui/image/qimage/tst_qimage.cpp | 24 +++ .../gui/image/qimagereader/tst_qimagereader.cpp | 1 + tests/auto/gui/painting/qpainter/tst_qpainter.cpp | 1 + .../qimageconversion/tst_qimageconversion.cpp | 22 ++ 14 files changed, 281 insertions(+), 66 deletions(-) diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 8e0bbb6907..b7f67cd7ef 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -287,6 +287,7 @@ bool QImageData::checkForAlphaPixels() const case QImage::Format_RGB555: case QImage::Format_RGB666: case QImage::Format_RGB888: + case QImage::Format_BGR888: case QImage::Format_RGBX8888: case QImage::Format_BGR30: case QImage::Format_RGB30: @@ -720,6 +721,7 @@ bool QImageData::checkForAlphaPixels() const \value Format_RGBA64 The image is stored using a 64-bit halfword-ordered RGBA format (16-16-16-16). (added in Qt 5.12) \value Format_RGBA64_Premultiplied The image is stored using a premultiplied 64-bit halfword-ordered RGBA format (16-16-16-16). (added in Qt 5.12) + \value Format_BGR888 The image is stored using a 24-bit BGR format. (added in Qt 5.14) \note Drawing into a QImage with QImage::Format_Indexed8 is not supported. @@ -5550,6 +5552,19 @@ static Q_CONSTEXPR QPixelFormat pixelformats[] = { /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied, /*INTERPRETATION*/ QPixelFormat::UnsignedShort, /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian), + //QImage::Format_BGR888: + QPixelFormat(QPixelFormat::BGR, + /*RED*/ 8, + /*GREEN*/ 8, + /*BLUE*/ 8, + /*FOURTH*/ 0, + /*FIFTH*/ 0, + /*ALPHA*/ 0, + /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha, + /*ALPHA POSITION*/ QPixelFormat::AtBeginning, + /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied, + /*INTERPRETATION*/ QPixelFormat::UnsignedByte, + /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian), }; Q_STATIC_ASSERT(sizeof(pixelformats) / sizeof(*pixelformats) == QImage::NImageFormats); diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h index 7c68168be8..7544ccca05 100644 --- a/src/gui/image/qimage.h +++ b/src/gui/image/qimage.h @@ -131,6 +131,7 @@ public: Format_RGBA64, Format_RGBA64_Premultiplied, Format_Grayscale16, + Format_BGR888, #ifndef Q_QDOC NImageFormats #endif diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index 837ac88470..539bac222a 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -429,8 +429,8 @@ typedef void (QT_FASTCALL *Rgb888ToRgbConverter)(quint32 *dst, const uchar *src, template static void convert_RGB888_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { - Q_ASSERT(src->format == QImage::Format_RGB888); - if (rgbx) + Q_ASSERT(src->format == QImage::Format_RGB888 || src->format == QImage::Format_BGR888); + if (rgbx ^ (src->format == QImage::Format_BGR888)) Q_ASSERT(dest->format == QImage::Format_RGBX8888 || dest->format == QImage::Format_RGBA8888 || dest->format == QImage::Format_RGBA8888_Premultiplied); else Q_ASSERT(dest->format == QImage::Format_RGB32 || dest->format == QImage::Format_ARGB32 || dest->format == QImage::Format_ARGB32_Premultiplied); @@ -1421,6 +1421,69 @@ static void convert_RGBA64_to_gray16(QImageData *dest, const QImageData *src, Qt } } +static void convert_RGB888_to_BGR888(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_RGB888 || src->format == QImage::Format_BGR888); + Q_ASSERT(dest->format == QImage::Format_RGB888 || dest->format == QImage::Format_BGR888); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const qsizetype sbpl = src->bytes_per_line; + const qsizetype dbpl = dest->bytes_per_line; + const uchar *src_data = src->data; + uchar *dest_data = dest->data; + + for (int i = 0; i < src->height; ++i) { + int pixel = 0; + // Handle 4 pixels (12 bytes) at a time + for (; pixel + 3 < src->width; pixel += 4) { + const uchar *src = src_data + pixel * 3; + quint32 *dest_packed = (quint32 *) (dest_data + pixel * 3); + dest_packed[0] = (src[5] << 24) | (src[0] << 16) | (src[1] << 8) | (src[2] << 0); + dest_packed[1] = (src[7] << 24) | (src[8] << 16) | (src[3] << 8) | (src[4] << 0); + dest_packed[2] = (src[9] << 24) | (src[10] << 16) | (src[11] << 8) | (src[6] << 0); + } + + // epilog: handle left over pixels + for (; pixel < src->width; ++pixel) { + dest_data[pixel * 3 + 0] = src_data[pixel * 3 + 2]; + dest_data[pixel * 3 + 1] = src_data[pixel * 3 + 1]; + dest_data[pixel * 3 + 2] = src_data[pixel * 3 + 0]; + } + + src_data += sbpl; + dest_data += dbpl; + } +} + +static bool convert_RGB888_to_BGR888_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_RGB888 || data->format == QImage::Format_BGR888); + + const qsizetype bpl = data->bytes_per_line; + uchar *line_data = data->data; + + for (int i = 0; i < data->height; ++i) { + for (int j = 0; j < data->width; ++j) + qSwap(line_data[j * 3 + 0], line_data[j * 3 + 2]); + line_data += bpl; + } + + switch (data->format) { + case QImage::Format_RGB888: + data->format = QImage::Format_BGR888; + break; + case QImage::Format_BGR888: + data->format = QImage::Format_RGB888; + break; + default: + Q_UNREACHABLE(); + data->format = QImage::Format_Invalid; + return false; + } + return true; +} + static QVector fix_color_table(const QVector &ctbl, QImage::Format format) { QVector colorTable = ctbl; @@ -2265,7 +2328,7 @@ static bool convert_Grayscale8_to_Indexed8_inplace(QImageData *data, Qt::ImageCo Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormats] = { { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, @@ -2286,7 +2349,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_Mono { @@ -2308,7 +2371,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_MonoLSB { @@ -2333,7 +2396,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, 0, 0, convert_Indexed8_to_Alpha8, convert_Indexed8_to_Grayscale8, - 0, 0, 0, 0 + 0, 0, 0, 0, 0 }, // Format_Indexed8 { @@ -2361,7 +2424,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_RGB_to_RGB30, 0, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0 }, // Format_RGB32 { @@ -2391,7 +2454,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, convert_ARGB32_to_RGBA64, - 0, 0 + 0, 0, 0 }, // Format_ARGB32 { @@ -2416,7 +2479,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_ARGB_to_RGBA, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0 }, // Format_ARGB32_Premultiplied { @@ -2438,7 +2501,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB16 { @@ -2460,7 +2523,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB8565_Premultiplied { @@ -2482,7 +2545,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB666 { @@ -2504,7 +2567,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB6666_Premultiplied { @@ -2526,7 +2589,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB555 { @@ -2548,7 +2611,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB8555_Premultiplied { @@ -2565,13 +2628,14 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, + 0, // self 0, 0, convert_RGB888_to_RGB, convert_RGB888_to_RGB, convert_RGB888_to_RGB, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + convert_RGB888_to_BGR888, }, // Format_RGB888 { @@ -2593,7 +2657,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB444 { @@ -2614,7 +2678,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB4444_Premultiplied { 0, @@ -2641,7 +2705,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_RGB_to_RGB30, 0, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0 }, // Format_RGBX8888 { 0, @@ -2670,7 +2734,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, convert_ARGB32_to_RGBA64, - 0, 0 + 0, 0, 0 }, // Format_RGBA8888 { @@ -2692,7 +2756,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGBA8888_Premultiplied { @@ -2720,7 +2784,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_BGR30_to_RGB30, convert_BGR30_to_RGB30, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0 }, // Format_BGR30 { 0, @@ -2747,7 +2811,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_A2RGB30_PM_to_RGB30, convert_BGR30_to_RGB30, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0 }, // Format_A2BGR30_Premultiplied { 0, @@ -2773,7 +2837,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_BGR30_to_RGB30, 0, convert_passthrough, - 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB30 { 0, @@ -2800,7 +2864,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_A2RGB30_PM_to_RGB30, 0, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0 }, // Format_A2RGB30_Premultiplied { 0, @@ -2820,7 +2884,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_Alpha8 { 0, @@ -2840,14 +2904,15 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_Grayscale8 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // self convert_passthrough, convert_passthrough, - convert_RGBA64_to_gray16 + convert_RGBA64_to_gray16, + 0 }, // Format_RGBX64 { 0, @@ -2874,6 +2939,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_RGBA64_to_RGBx64, 0, // self convert_RGBA64_to_RGBA64PM, + 0, 0 }, // Format_RGBA64 { @@ -2901,7 +2967,8 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_RGBA64PM_to_RGBA64, convert_RGBA64PM_to_RGBA64, 0, // self - convert_RGBA64_to_gray16 + convert_RGBA64_to_gray16, + 0 }, // Format_RGBA64_Premultiplied { 0, @@ -2931,20 +2998,46 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_gray16_to_RGBA64, convert_gray16_to_RGBA64, convert_gray16_to_RGBA64, - 0 // self + 0, // self + 0 }, // Format_Grayscale16 + { + 0, + 0, + 0, + 0, + 0, 0, 0, + 0, + 0, + 0, + 0, + 0, + 0, + convert_RGB888_to_BGR888, + 0, + 0, +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + convert_RGB888_to_RGB, + convert_RGB888_to_RGB, + convert_RGB888_to_RGB, +#else + 0, 0, 0, +#endif + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, // self + }, // Format_BGR888 }; InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats] = { { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_Mono { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_MonoLSB { 0, @@ -2968,7 +3061,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, 0, 0, convert_Indexed8_to_Alpha8_inplace, convert_Indexed8_to_Grayscale8_inplace, - 0, 0, 0, 0 + 0, 0, 0, 0, 0 }, // Format_Indexed8 { 0, @@ -2995,7 +3088,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma convert_RGB_to_RGB30_inplace, 0, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0 }, // Format_RGB32 { 0, @@ -3022,7 +3115,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma convert_RGB_to_RGB30_inplace, 0, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0 }, // Format_ARGB32 { 0, @@ -3046,34 +3139,35 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma convert_ARGB_to_RGBA_inplace, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0 }, // Format_ARGB32_Premultiplied { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB16 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB8565_Premultiplied { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB666 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB6666_Premultiplied { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB555 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB8555_Premultiplied { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + convert_RGB888_to_BGR888_inplace }, // Format_RGB888 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB444 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB4444_Premultiplied { 0, @@ -3100,7 +3194,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma convert_RGB_to_RGB30_inplace, 0, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0 }, // Format_RGBX8888 { 0, @@ -3127,7 +3221,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma convert_RGB_to_RGB30_inplace, 0, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0 }, // Format_RGBA8888 { 0, @@ -3149,7 +3243,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGBA8888_Premultiplied { 0, @@ -3176,7 +3270,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma convert_BGR30_to_RGB30_inplace, convert_BGR30_to_A2RGB30_inplace, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0 }, // Format_BGR30 { 0, @@ -3202,7 +3296,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, // self convert_A2RGB30_PM_to_RGB30_inplace, convert_BGR30_to_RGB30_inplace, - 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_A2BGR30_Premultiplied { 0, @@ -3228,7 +3322,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma convert_BGR30_to_A2RGB30_inplace, 0, // self convert_passthrough_inplace, - 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB30 { 0, @@ -3255,7 +3349,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma convert_A2RGB30_PM_to_RGB30_inplace, 0, // self 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0 }, // Format_A2RGB30_Premultiplied { 0, @@ -3280,7 +3374,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, 0, 0, // self 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0 }, // Format_Alpha8 { 0, @@ -3305,32 +3399,37 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, 0, 0, 0, // self - 0, 0, 0, 0 + 0, 0, 0, 0, 0 }, // Format_Grayscale8 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // self convert_passthrough_inplace, convert_passthrough_inplace, - 0 + 0, 0 }, // Format_RGBX64 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, convert_RGBA64_to_RGBx64_inplace, 0, // self convert_RGBA64_to_RGBA64PM_inplace, - 0 + 0, 0 }, // Format_RGBA64 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, convert_RGBA64PM_to_RGBA64_inplace, convert_RGBA64PM_to_RGBA64_inplace, 0, // self - 0 + 0, 0 }, // Format_RGBA64_Premultiplied { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_Grayscale16 + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + convert_RGB888_to_BGR888_inplace, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, // Format_BGR888 }; static void qInitImageConversions() @@ -3341,6 +3440,9 @@ static void qInitImageConversions() qimage_converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_ssse3; qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_ssse3; qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_ssse3; + qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBX8888] = convert_RGB888_to_RGB32_ssse3; + qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBA8888] = convert_RGB888_to_RGB32_ssse3; + qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBA8888_Premultiplied] = convert_RGB888_to_RGB32_ssse3; } #endif diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h index 9da6acd0a7..9e2d9c86bb 100644 --- a/src/gui/image/qimage_p.h +++ b/src/gui/image/qimage_p.h @@ -207,6 +207,7 @@ inline int qt_depthForFormat(QImage::Format format) case QImage::Format_ARGB8565_Premultiplied: case QImage::Format_ARGB8555_Premultiplied: case QImage::Format_RGB888: + case QImage::Format_BGR888: depth = 24; break; case QImage::Format_RGBX64: diff --git a/src/gui/image/qimage_ssse3.cpp b/src/gui/image/qimage_ssse3.cpp index 9cdfba20e3..fb81a1a6c3 100644 --- a/src/gui/image/qimage_ssse3.cpp +++ b/src/gui/image/qimage_ssse3.cpp @@ -121,8 +121,11 @@ Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_ssse3(quint32 *dst, con void convert_RGB888_to_RGB32_ssse3(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { - Q_ASSERT(src->format == QImage::Format_RGB888); - Q_ASSERT(dest->format == QImage::Format_RGB32 || dest->format == QImage::Format_ARGB32 || dest->format == QImage::Format_ARGB32_Premultiplied); + Q_ASSERT(src->format == QImage::Format_RGB888 || src->format == QImage::Format_BGR888); + if (src->format == QImage::Format_BGR888) + Q_ASSERT(dest->format == QImage::Format_RGBX8888 || dest->format == QImage::Format_RGBA8888 || dest->format == QImage::Format_RGBA8888_Premultiplied); + else + Q_ASSERT(dest->format == QImage::Format_RGB32 || dest->format == QImage::Format_ARGB32 || dest->format == QImage::Format_ARGB32_Premultiplied); Q_ASSERT(src->width == dest->width); Q_ASSERT(src->height == dest->height); diff --git a/src/gui/image/qpixmap_win.cpp b/src/gui/image/qpixmap_win.cpp index 3a2db74098..8aad77b991 100644 --- a/src/gui/image/qpixmap_win.cpp +++ b/src/gui/image/qpixmap_win.cpp @@ -281,6 +281,7 @@ Q_GUI_EXPORT HBITMAP qt_imageToWinHBITMAP(const QImage &imageIn, int hbitmapForm } break; case QImage::Format_RGB888: + case QImage::Format_BGR888: compression = BI_RGB; bitCount = 24u; break; @@ -368,7 +369,7 @@ static QImage::Format imageFromWinHBITMAP_Format(const BITMAPINFOHEADER &header, ? QImage::Format_RGB32 : QImage::Format_ARGB32_Premultiplied; break; case 24: - result = QImage::Format_RGB888; + result = QImage::Format_BGR888; break; case 16: result = QImage::Format_RGB555; diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp index 16d6c25b8b..4ab45337b0 100644 --- a/src/gui/image/qpnghandler.cpp +++ b/src/gui/image/qpnghandler.cpp @@ -1079,6 +1079,7 @@ bool QPNGImageWriter::writeImage(const QImage& image, volatile int compression_i if (color_type == PNG_COLOR_TYPE_RGB) { switch (image.format()) { case QImage::Format_RGB888: + case QImage::Format_BGR888: break; case QImage::Format_RGBX8888: case QImage::Format_RGBX64: @@ -1131,6 +1132,7 @@ bool QPNGImageWriter::writeImage(const QImage& image, volatile int compression_i case QImage::Format_RGB32: case QImage::Format_ARGB32: case QImage::Format_RGB888: + case QImage::Format_BGR888: case QImage::Format_RGBX8888: case QImage::Format_RGBA8888: case QImage::Format_RGBX64: diff --git a/src/gui/opengl/qopengltextureuploader.cpp b/src/gui/opengl/qopengltextureuploader.cpp index d9d5403cf3..9e393bc47a 100644 --- a/src/gui/opengl/qopengltextureuploader.cpp +++ b/src/gui/opengl/qopengltextureuploader.cpp @@ -65,6 +65,10 @@ #define GL_RGBA16 0x805B #endif +#ifndef GL_BGR +#define GL_BGR 0x80E0 +#endif + #ifndef GL_BGRA #define GL_BGRA 0x80E1 #endif @@ -202,6 +206,20 @@ qsizetype QOpenGLTextureUploader::textureImage(GLenum target, const QImage &imag pixelType = GL_UNSIGNED_BYTE; targetFormat = QImage::Format_RGB888; break; + case QImage::Format_BGR888: + if (isOpenGL12orBetter) { + externalFormat = GL_BGR; + internalFormat = GL_RGB; + pixelType = GL_UNSIGNED_BYTE; + targetFormat = QImage::Format_BGR888; + } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) { + funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED); + funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_BLUE); + externalFormat = internalFormat = GL_RGB; + pixelType = GL_UNSIGNED_BYTE; + targetFormat = QImage::Format_BGR888; + } + break; case QImage::Format_RGBX8888: case QImage::Format_RGBA8888: case QImage::Format_RGBA8888_Premultiplied: diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 55d69221f5..c17bf2ddfd 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -88,6 +88,7 @@ template<> Q_DECL_CONSTEXPR uint redWidth() { return 4; } template<> Q_DECL_CONSTEXPR uint redWidth() { return 5; } template<> Q_DECL_CONSTEXPR uint redWidth() { return 6; } template<> Q_DECL_CONSTEXPR uint redWidth() { return 8; } +template<> Q_DECL_CONSTEXPR uint redWidth() { return 8; } template<> Q_DECL_CONSTEXPR uint redWidth() { return 4; } template<> Q_DECL_CONSTEXPR uint redWidth() { return 5; } template<> Q_DECL_CONSTEXPR uint redWidth() { return 5; } @@ -101,6 +102,7 @@ template<> Q_DECL_CONSTEXPR uint redShift() { return 8; template<> Q_DECL_CONSTEXPR uint redShift() { return 10; } template<> Q_DECL_CONSTEXPR uint redShift() { return 12; } template<> Q_DECL_CONSTEXPR uint redShift() { return 16; } +template<> Q_DECL_CONSTEXPR uint redShift() { return 0; } template<> Q_DECL_CONSTEXPR uint redShift() { return 8; } template<> Q_DECL_CONSTEXPR uint redShift() { return 18; } template<> Q_DECL_CONSTEXPR uint redShift() { return 19; } @@ -119,6 +121,7 @@ template<> Q_DECL_CONSTEXPR uint greenWidth() { return 4; template<> Q_DECL_CONSTEXPR uint greenWidth() { return 5; } template<> Q_DECL_CONSTEXPR uint greenWidth() { return 6; } template<> Q_DECL_CONSTEXPR uint greenWidth() { return 8; } +template<> Q_DECL_CONSTEXPR uint greenWidth() { return 8; } template<> Q_DECL_CONSTEXPR uint greenWidth() { return 4; } template<> Q_DECL_CONSTEXPR uint greenWidth() { return 5; } template<> Q_DECL_CONSTEXPR uint greenWidth() { return 6; } @@ -132,6 +135,7 @@ template<> Q_DECL_CONSTEXPR uint greenShift() { return 4; template<> Q_DECL_CONSTEXPR uint greenShift() { return 5; } template<> Q_DECL_CONSTEXPR uint greenShift() { return 6; } template<> Q_DECL_CONSTEXPR uint greenShift() { return 8; } +template<> Q_DECL_CONSTEXPR uint greenShift() { return 8; } template<> Q_DECL_CONSTEXPR uint greenShift() { return 4; } template<> Q_DECL_CONSTEXPR uint greenShift() { return 13; } template<> Q_DECL_CONSTEXPR uint greenShift() { return 13; } @@ -150,6 +154,7 @@ template<> Q_DECL_CONSTEXPR uint blueWidth() { return 4; template<> Q_DECL_CONSTEXPR uint blueWidth() { return 5; } template<> Q_DECL_CONSTEXPR uint blueWidth() { return 6; } template<> Q_DECL_CONSTEXPR uint blueWidth() { return 8; } +template<> Q_DECL_CONSTEXPR uint blueWidth() { return 8; } template<> Q_DECL_CONSTEXPR uint blueWidth() { return 4; } template<> Q_DECL_CONSTEXPR uint blueWidth() { return 5; } template<> Q_DECL_CONSTEXPR uint blueWidth() { return 5; } @@ -163,6 +168,7 @@ template<> Q_DECL_CONSTEXPR uint blueShift() { return 0; template<> Q_DECL_CONSTEXPR uint blueShift() { return 0; } template<> Q_DECL_CONSTEXPR uint blueShift() { return 0; } template<> Q_DECL_CONSTEXPR uint blueShift() { return 0; } +template<> Q_DECL_CONSTEXPR uint blueShift() { return 16; } template<> Q_DECL_CONSTEXPR uint blueShift() { return 0; } template<> Q_DECL_CONSTEXPR uint blueShift() { return 8; } template<> Q_DECL_CONSTEXPR uint blueShift() { return 8; } @@ -181,6 +187,7 @@ template<> Q_DECL_CONSTEXPR uint alphaWidth() { return 0; template<> Q_DECL_CONSTEXPR uint alphaWidth() { return 0; } template<> Q_DECL_CONSTEXPR uint alphaWidth() { return 0; } template<> Q_DECL_CONSTEXPR uint alphaWidth() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaWidth() { return 0; } template<> Q_DECL_CONSTEXPR uint alphaWidth() { return 4; } template<> Q_DECL_CONSTEXPR uint alphaWidth() { return 8; } template<> Q_DECL_CONSTEXPR uint alphaWidth() { return 8; } @@ -194,6 +201,7 @@ template<> Q_DECL_CONSTEXPR uint alphaShift() { return 0; template<> Q_DECL_CONSTEXPR uint alphaShift() { return 0; } template<> Q_DECL_CONSTEXPR uint alphaShift() { return 0; } template<> Q_DECL_CONSTEXPR uint alphaShift() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaShift() { return 0; } template<> Q_DECL_CONSTEXPR uint alphaShift() { return 12; } template<> Q_DECL_CONSTEXPR uint alphaShift() { return 0; } template<> Q_DECL_CONSTEXPR uint alphaShift() { return 0; } @@ -214,6 +222,7 @@ template<> constexpr QPixelLayout::BPP bitsPerPixel() { r template<> constexpr QPixelLayout::BPP bitsPerPixel() { return QPixelLayout::BPP16; } template<> constexpr QPixelLayout::BPP bitsPerPixel() { return QPixelLayout::BPP24; } template<> constexpr QPixelLayout::BPP bitsPerPixel() { return QPixelLayout::BPP24; } +template<> constexpr QPixelLayout::BPP bitsPerPixel() { return QPixelLayout::BPP24; } template<> constexpr QPixelLayout::BPP bitsPerPixel() { return QPixelLayout::BPP16; } template<> constexpr QPixelLayout::BPP bitsPerPixel() { return QPixelLayout::BPP24; } template<> constexpr QPixelLayout::BPP bitsPerPixel() { return QPixelLayout::BPP24; } @@ -1528,7 +1537,8 @@ QPixelLayout qPixelLayouts[QImage::NImageFormats] = { { false, false, QPixelLayout::BPP16, nullptr, convertGrayscale16ToRGB32, convertGrayscale16ToRGBA64, fetchGrayscale16ToRGB32, fetchGrayscale16ToRGBA64, - storeGrayscale16FromARGB32PM, storeGrayscale16FromRGB32 } // Format_Grayscale16 + storeGrayscale16FromARGB32PM, storeGrayscale16FromRGB32 }, // Format_Grayscale16 + pixelLayoutRGB(), }; Q_STATIC_ASSERT(sizeof(qPixelLayouts) / sizeof(*qPixelLayouts) == QImage::NImageFormats); @@ -1643,7 +1653,8 @@ ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats] = { storeRGBX64FromRGBA64PM, storeRGBA64FromRGBA64PM, storeRGBA64PMFromRGBA64PM, - storeGray16FromRGBA64PM + storeGray16FromRGBA64PM, + storeGenericFromRGBA64PM, }; /* @@ -1732,6 +1743,7 @@ static DestFetchProc destFetchProc[QImage::NImageFormats] = destFetch, // Format_RGBA64 destFetch, // Format_RGBA64_Premultiplied destFetch, // Format_Grayscale16 + destFetch, // Format_BGR888 }; #if QT_CONFIG(raster_64bit) @@ -1782,6 +1794,7 @@ static DestFetchProc64 destFetchProc64[QImage::NImageFormats] = destFetch64, // Format_RGBA64 destFetchRGB64, // Format_RGBA64_Premultiplied destFetch64, // Format_Grayscale16 + destFetch64, // Format_BGR888 }; #endif @@ -1922,6 +1935,7 @@ static DestStoreProc destStoreProc[QImage::NImageFormats] = destStore, // Format_RGBA64 destStore, // Format_RGBA64_Premultiplied destStore, // Format_Grayscale16 + destStore, // Format_BGR888 }; #if QT_CONFIG(raster_64bit) @@ -1971,6 +1985,7 @@ static DestStoreProc64 destStoreProc64[QImage::NImageFormats] = destStore64RGBA64, // Format_RGBA64 0, // Format_RGBA64_Premultiplied destStore64, // Format_Grayscale16 + destStore64, // Format_BGR888 }; #endif @@ -3922,6 +3937,7 @@ static SourceFetchProc sourceFetchUntransformed[QImage::NImageFormats] = { fetchUntransformed, // RGBA64 fetchUntransformed, // RGBA64_Premultiplied fetchUntransformed, // Grayscale16 + fetchUntransformed, // BGR888 }; static const SourceFetchProc sourceFetchGeneric[NBlendTypes] = { @@ -6589,6 +6605,14 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = qt_alphargbblit_generic, qt_rectfill_quint16 }, + // Format_BGR888 + { + blend_color_generic, + 0, + qt_alphamapblit_generic, + qt_alphargbblit_generic, + qt_rectfill_quint24 + }, }; #if !defined(__SSE2__) diff --git a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp index dc7ea08dc5..cb8962d4b8 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp +++ b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp @@ -188,7 +188,7 @@ static QImage::Format determineFormat(const fb_var_screeninfo &info, int depth) if (memcmp(rgba, rgb888, 3 * sizeof(fb_bitfield)) == 0) { format = QImage::Format_RGB888; } else if (memcmp(rgba, bgr888, 3 * sizeof(fb_bitfield)) == 0) { - format = QImage::Format_RGB888; + format = QImage::Format_BGR888; // pixeltype = BGRPixel; } break; diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp index 441ec17412..b84aa52465 100644 --- a/tests/auto/gui/image/qimage/tst_qimage.cpp +++ b/tests/auto/gui/image/qimage/tst_qimage.cpp @@ -303,6 +303,8 @@ static QLatin1String formatToString(QImage::Format format) return QLatin1String("RGBA64pm"); case QImage::Format_Grayscale16: return QLatin1String("Grayscale16"); + case QImage::Format_BGR888: + return QLatin1String("BGR888"); default: break; }; @@ -844,6 +846,13 @@ void tst_QImage::convertToFormat_data() QTest::newRow("blue rgb32 -> rgb888") << int(QImage::Format_RGB32) << 0xff0000ff << int(QImage::Format_RGB888) << 0xff0000ff; + QTest::newRow("red rgb32 -> bgr888") << int(QImage::Format_RGB32) << 0xffff0000 + << int(QImage::Format_BGR888) << 0xffff0000; + QTest::newRow("green rgb32 -> bgr888") << int(QImage::Format_RGB32) << 0xff00ff00 + << int(QImage::Format_BGR888) << 0xff00ff00; + QTest::newRow("blue rgb32 -> bgr888") << int(QImage::Format_RGB32) << 0xff0000ff + << int(QImage::Format_BGR888) << 0xff0000ff; + QTest::newRow("red rgb16 -> rgb888") << int(QImage::Format_RGB16) << 0xffff0000 << int(QImage::Format_RGB888) << 0xffff0000; QTest::newRow("green rgb16 -> rgb888") << int(QImage::Format_RGB16) << 0xff00ff00 @@ -858,6 +867,13 @@ void tst_QImage::convertToFormat_data() QTest::newRow("blue rgb888 -> argb32") << int(QImage::Format_RGB888) << 0xff0000ff << int(QImage::Format_ARGB32) << 0xff0000ff; + QTest::newRow("red bgr888 -> argb32") << int(QImage::Format_RGB888) << 0xffff0000 + << int(QImage::Format_ARGB32) << 0xffff0000; + QTest::newRow("green bgr888 -> argb32") << int(QImage::Format_RGB888) << 0xff00ff00 + << int(QImage::Format_ARGB32) << 0xff00ff00; + QTest::newRow("blue bgr888 -> argb32") << int(QImage::Format_RGB888) << 0xff0000ff + << int(QImage::Format_ARGB32) << 0xff0000ff; + QTest::newRow("red rgb888 -> rgbx8888") << int(QImage::Format_RGB888) << 0xffff0000 << int(QImage::Format_RGBX8888) << 0xffff0000; QTest::newRow("green rgb888 -> rgbx8888") << int(QImage::Format_RGB888) << 0xff00ff00 @@ -1338,6 +1354,12 @@ void tst_QImage::setPixel_data() << 0xff00ff00 << 0x00ff00u; QTest::newRow("RGB888 blue") << int(QImage::Format_RGB888) << 0xff0000ff << 0x0000ffu; + QTest::newRow("BGR888 red") << int(QImage::Format_BGR888) + << 0xffff0000 << 0x0000ffu; + QTest::newRow("BGR888 green") << int(QImage::Format_BGR888) + << 0xff00ff00 << 0x00ff00u; + QTest::newRow("BGR888 blue") << int(QImage::Format_BGR888) + << 0xff0000ff << 0xff0000u; #if Q_BYTE_ORDER == Q_BIG_ENDIAN QTest::newRow("RGBA8888 red") << int(QImage::Format_RGBA8888) << 0xffff0000u << 0xff0000ffu; @@ -1425,6 +1447,7 @@ void tst_QImage::setPixel() case int(QImage::Format_ARGB8565_Premultiplied): case int(QImage::Format_ARGB8555_Premultiplied): case int(QImage::Format_RGB888): + case int(QImage::Format_BGR888): { for (int y = 0; y < h; ++y) { const quint24 *row = (const quint24*)(img.scanLine(y)); @@ -2445,6 +2468,7 @@ void tst_QImage::mirrored_data() QTest::newRow("Format_RGB555, vertical") << QImage::Format_RGB555 << true << false << 16 << 16; QTest::newRow("Format_ARGB8555_Premultiplied, vertical") << QImage::Format_ARGB8555_Premultiplied << true << false << 16 << 16; QTest::newRow("Format_RGB888, vertical") << QImage::Format_RGB888 << true << false << 16 << 16; + QTest::newRow("Format_BGR888, vertical") << QImage::Format_BGR888 << true << false << 16 << 16; QTest::newRow("Format_RGB444, vertical") << QImage::Format_RGB444 << true << false << 16 << 16; QTest::newRow("Format_RGBX8888, vertical") << QImage::Format_RGBX8888 << true << false << 16 << 16; QTest::newRow("Format_RGBA8888_Premultiplied, vertical") << QImage::Format_RGBA8888_Premultiplied << true << false << 16 << 16; diff --git a/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp index eeabfd0413..f6ffd7b7c5 100644 --- a/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp +++ b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp @@ -1863,6 +1863,7 @@ void tst_QImageReader::saveFormat_data() QTest::newRow("Format_RGB555") << QImage::Format_RGB555; QTest::newRow("Format_ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied; QTest::newRow("Format_RGB888") << QImage::Format_RGB888; + QTest::newRow("Format_BGR888") << QImage::Format_BGR888; QTest::newRow("Format_RGB444") << QImage::Format_RGB444; QTest::newRow("Format_ARGB4444_Premultiplied") << QImage::Format_ARGB4444_Premultiplied; QTest::newRow("Format_RGBA64") << QImage::Format_RGBA64; diff --git a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp index 0efeb9b356..61867ec65a 100644 --- a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp +++ b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp @@ -1637,6 +1637,7 @@ void tst_QPainter::qimageFormats_data() QTest::newRow("Qimage::Format_RGB555") << QImage::Format_RGB555; QTest::newRow("Qimage::Format_ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied; QTest::newRow("Qimage::Format_RGB888") << QImage::Format_RGB888; + QTest::newRow("Qimage::Format_BGR888") << QImage::Format_BGR888; QTest::newRow("Qimage::Format_A2RGB30_Premultiplied") << QImage::Format_A2RGB30_Premultiplied; QTest::newRow("Qimage::Format_RGB30") << QImage::Format_RGB30; } diff --git a/tests/benchmarks/gui/image/qimageconversion/tst_qimageconversion.cpp b/tests/benchmarks/gui/image/qimageconversion/tst_qimageconversion.cpp index 570c7b59fa..b88669e9ce 100644 --- a/tests/benchmarks/gui/image/qimageconversion/tst_qimageconversion.cpp +++ b/tests/benchmarks/gui/image/qimageconversion/tst_qimageconversion.cpp @@ -183,6 +183,7 @@ void tst_QImageConversion::convertRgb32_data() QTest::newRow("rgb32 -> rgb30") << rgb32 << QImage::Format_RGB30; QTest::newRow("rgb32 -> a2bgr30") << rgb32 << QImage::Format_A2BGR30_Premultiplied; QTest::newRow("rgb32 -> rgb888") << rgb32 << QImage::Format_RGB888; + QTest::newRow("rgb32 -> bgr888") << rgb32 << QImage::Format_BGR888; QTest::newRow("rgb32 -> rgb666") << rgb32 << QImage::Format_RGB666; QTest::newRow("rgb32 -> rgb555") << rgb32 << QImage::Format_RGB555; QTest::newRow("rgb32 -> argb8565pm") << rgb32 << QImage::Format_ARGB8565_Premultiplied; @@ -196,6 +197,7 @@ void tst_QImageConversion::convertRgb32_data() QTest::newRow("argb32 -> rgb30") << argb32 << QImage::Format_RGB30; QTest::newRow("argb32 -> a2bgr30") << argb32 << QImage::Format_A2BGR30_Premultiplied; QTest::newRow("argb32 -> rgb888") << argb32 << QImage::Format_RGB888; + QTest::newRow("argb32 -> bgr888") << argb32 << QImage::Format_BGR888; QTest::newRow("argb32 -> rgb666") << argb32 << QImage::Format_RGB666; QTest::newRow("argb32 -> argb8565pm") << argb32 << QImage::Format_ARGB8565_Premultiplied; QTest::newRow("argb32 -> argb4444pm") << argb32 << QImage::Format_ARGB4444_Premultiplied; @@ -212,6 +214,7 @@ void tst_QImageConversion::convertRgb32_data() QTest::newRow("argb32pm -> rgb30") << argb32pm << QImage::Format_RGB30; QTest::newRow("argb32pm -> a2bgr30") << argb32pm << QImage::Format_A2BGR30_Premultiplied; QTest::newRow("argb32pm -> rgb888") << argb32pm << QImage::Format_RGB888; + QTest::newRow("argb32pm -> bgr888") << argb32pm << QImage::Format_BGR888; QTest::newRow("argb32pm -> rgb666") << argb32pm << QImage::Format_RGB666; QTest::newRow("argb32pm -> argb8565pm") << argb32pm << QImage::Format_ARGB8565_Premultiplied; QTest::newRow("argb32pm -> argb4444pm") << argb32pm << QImage::Format_ARGB4444_Premultiplied; @@ -242,6 +245,8 @@ void tst_QImageConversion::convertGeneric_data() QImage rgb666 = rgb32.convertToFormat(QImage::Format_RGB666); QImage argb4444 = argb32.convertToFormat(QImage::Format_ARGB4444_Premultiplied); QImage rgba64pm = argb32.convertToFormat(QImage::Format_RGBA64_Premultiplied); + QImage rgb888 = rgb32.convertToFormat(QImage::Format_RGB888); + QImage bgr888 = rgb32.convertToFormat(QImage::Format_BGR888); QTest::newRow("indexed8 -> rgb32") << i8 << QImage::Format_RGB32; QTest::newRow("indexed8 -> argb32") << i8 << QImage::Format_ARGB32; @@ -299,6 +304,20 @@ void tst_QImageConversion::convertGeneric_data() QTest::newRow("rgba64pm -> rgb30") << rgba64pm << QImage::Format_RGB30; QTest::newRow("rgba64pm -> a2bgr30") << rgba64pm << QImage::Format_A2BGR30_Premultiplied; QTest::newRow("rgba64pm -> rgba64") << rgba64pm << QImage::Format_RGBA64; + + QTest::newRow("rgb888 -> rgb32") << rgb888 << QImage::Format_RGB32; + QTest::newRow("rgb888 -> argb32") << rgb888 << QImage::Format_ARGB32; + QTest::newRow("rgb888 -> argb32pm") << rgb888 << QImage::Format_ARGB32_Premultiplied; + QTest::newRow("rgb888 -> rgbx8888") << rgb888 << QImage::Format_RGBX8888; + QTest::newRow("rgb888 -> rgba8888pm") << rgb888 << QImage::Format_RGBA8888_Premultiplied; + QTest::newRow("rgb888 -> bgr888") << rgb888 << QImage::Format_BGR888; + + QTest::newRow("bgr888 -> rgb32") << bgr888 << QImage::Format_RGB32; + QTest::newRow("bgr888 -> argb32") << bgr888 << QImage::Format_ARGB32; + QTest::newRow("bgr888 -> argb32pm") << bgr888 << QImage::Format_ARGB32_Premultiplied; + QTest::newRow("bgr888 -> rgbx8888") << bgr888 << QImage::Format_RGBX8888; + QTest::newRow("bgr888 -> rgba8888pm") << bgr888 << QImage::Format_RGBA8888_Premultiplied; + QTest::newRow("bgr888 -> rgb888") << bgr888 << QImage::Format_RGB888; } void tst_QImageConversion::convertGeneric() @@ -323,6 +342,7 @@ void tst_QImageConversion::convertGenericInplace_data() QImage argb6666 = argb32.convertToFormat(QImage::Format_ARGB6666_Premultiplied); QImage argb4444 = argb32.convertToFormat(QImage::Format_ARGB4444_Premultiplied); QImage rgb16 = argb32.convertToFormat(QImage::Format_RGB16); + QImage rgb888 = argb32.convertToFormat(QImage::Format_RGB888); QTest::newRow("argb32 -> argb32pm -> argb32") << argb32 << QImage::Format_ARGB32_Premultiplied; QTest::newRow("argb32 -> rgb32 -> argb32") << argb32 << QImage::Format_RGB32; @@ -349,6 +369,8 @@ void tst_QImageConversion::convertGenericInplace_data() QTest::newRow("rgb16 -> rgb555 -> rgb16") << rgb16 << QImage::Format_RGB555; QTest::newRow("rgb16 -> rgb444 -> rgb16") << rgb16 << QImage::Format_RGB444; QTest::newRow("rgb16 -> argb4444pm -> rgb16") << rgb16 << QImage::Format_ARGB4444_Premultiplied; + + QTest::newRow("rgb888 -> bgr888 -> rgb888") << rgb888 << QImage::Format_BGR888; } void tst_QImageConversion::convertGenericInplace() -- cgit v1.2.3 From 1b7ce85a606261936efd3b3c7d73a71b5884e426 Mon Sep 17 00:00:00 2001 From: Sona Kurazyan Date: Tue, 30 Jul 2019 16:42:12 +0200 Subject: Remove usages of deprecated APIs of QWheelEvent - Replaced the usages of deprecated QWheelEvent::delta() and QWheelEvent::orientation() with QWheelEvent::angleDelta(). In most of the examples it is acceptable to use only the vertical component of angle delta. - Made the docs APIs to build conditionally, based on the deprecation version. Task-number: QTBUG-76491 Task-number: QTBUG-76540 Change-Id: Id4230d483f724af49e4b6349b44881c3944de2a2 Reviewed-by: Volker Hilsheimer --- examples/corelib/threads/doc/src/mandelbrot.qdoc | 4 ++-- examples/corelib/threads/mandelbrot/mandelbrotwidget.cpp | 2 +- examples/widgets/graphicsview/chip/view.cpp | 2 +- examples/widgets/graphicsview/elasticnodes/graphwidget.cpp | 2 +- examples/widgets/painting/affine/xform.cpp | 2 +- examples/widgets/widgets/mousebuttons/buttontester.cpp | 11 ++++++----- src/gui/kernel/qevent.cpp | 4 ++++ 7 files changed, 16 insertions(+), 11 deletions(-) diff --git a/examples/corelib/threads/doc/src/mandelbrot.qdoc b/examples/corelib/threads/doc/src/mandelbrot.qdoc index 274874632e..9e3fdc1dfe 100644 --- a/examples/corelib/threads/doc/src/mandelbrot.qdoc +++ b/examples/corelib/threads/doc/src/mandelbrot.qdoc @@ -304,8 +304,8 @@ \snippet threads/mandelbrot/mandelbrotwidget.cpp 12 The wheel event handler is reimplemented to make the mouse wheel - control the zoom level. QWheelEvent::delta() returns the angle of - the wheel mouse movement, in eights of a degree. For most mice, + control the zoom level. QWheelEvent::angleDelta() returns the angle + of the wheel mouse movement, in eighths of a degree. For most mice, one wheel step corresponds to 15 degrees. We find out how many mouse steps we have and determine the resulting zoom factor. For example, if we have two wheel steps in the positive direction diff --git a/examples/corelib/threads/mandelbrot/mandelbrotwidget.cpp b/examples/corelib/threads/mandelbrot/mandelbrotwidget.cpp index 71d0abb09f..822791533b 100644 --- a/examples/corelib/threads/mandelbrot/mandelbrotwidget.cpp +++ b/examples/corelib/threads/mandelbrot/mandelbrotwidget.cpp @@ -176,7 +176,7 @@ void MandelbrotWidget::keyPressEvent(QKeyEvent *event) //! [12] void MandelbrotWidget::wheelEvent(QWheelEvent *event) { - int numDegrees = event->delta() / 8; + int numDegrees = event->angleDelta().y() / 8; double numSteps = numDegrees / 15.0f; zoom(pow(ZoomInFactor, numSteps)); } diff --git a/examples/widgets/graphicsview/chip/view.cpp b/examples/widgets/graphicsview/chip/view.cpp index 9676c13ff7..7d5fd699a4 100644 --- a/examples/widgets/graphicsview/chip/view.cpp +++ b/examples/widgets/graphicsview/chip/view.cpp @@ -68,7 +68,7 @@ void GraphicsView::wheelEvent(QWheelEvent *e) { if (e->modifiers() & Qt::ControlModifier) { - if (e->delta() > 0) + if (e->angleDelta().y() > 0) view->zoomIn(6); else view->zoomOut(6); diff --git a/examples/widgets/graphicsview/elasticnodes/graphwidget.cpp b/examples/widgets/graphicsview/elasticnodes/graphwidget.cpp index 6b817b2a21..9341d77f8d 100644 --- a/examples/widgets/graphicsview/elasticnodes/graphwidget.cpp +++ b/examples/widgets/graphicsview/elasticnodes/graphwidget.cpp @@ -190,7 +190,7 @@ void GraphWidget::timerEvent(QTimerEvent *event) //! [5] void GraphWidget::wheelEvent(QWheelEvent *event) { - scaleView(pow((double)2, -event->delta() / 240.0)); + scaleView(pow((double)2, -event->angleDelta().y() / 240.0)); } //! [5] #endif diff --git a/examples/widgets/painting/affine/xform.cpp b/examples/widgets/painting/affine/xform.cpp index 482e0f3268..50acf0f814 100644 --- a/examples/widgets/painting/affine/xform.cpp +++ b/examples/widgets/painting/affine/xform.cpp @@ -260,7 +260,7 @@ void XFormView::timerEvent(QTimerEvent *e) #if QT_CONFIG(wheelevent) void XFormView::wheelEvent(QWheelEvent *e) { - m_scale += e->delta() / qreal(600); + m_scale += e->angleDelta().y() / qreal(600); m_scale = qMax(qreal(0.1), qMin(qreal(4), m_scale)); emit scaleChanged(int(m_scale*1000)); } diff --git a/examples/widgets/widgets/mousebuttons/buttontester.cpp b/examples/widgets/widgets/mousebuttons/buttontester.cpp index 6653221698..88dbbeda45 100644 --- a/examples/widgets/widgets/mousebuttons/buttontester.cpp +++ b/examples/widgets/widgets/mousebuttons/buttontester.cpp @@ -93,15 +93,16 @@ void ButtonTester::mouseDoubleClickEvent(QMouseEvent *e) void ButtonTester::wheelEvent (QWheelEvent *e) { QString result; - if (e->delta() > 0) { - - if (e->orientation() == Qt::Vertical) { + const bool vertical = qAbs(e->angleDelta().y()) >= qAbs(e->angleDelta().x()); + const int delta = vertical ? e->angleDelta().y() : e->angleDelta().x(); + if (delta > 0) { + if (vertical) { result = "Mouse Wheel Event: UP"; } else { result = "Mouse Wheel Event: LEFT"; } - } else if (e->delta() < 0) { - if (e->orientation() == Qt::Vertical) { + } else if (delta < 0) { + if (vertical) { result = "Mouse Wheel Event: DOWN"; } else { result = "Mouse Wheel Event: RIGHT"; diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index d79066adf2..616cca1422 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -743,12 +743,14 @@ QHoverEvent::~QHoverEvent() \l inverted always returns false. */ +#if QT_DEPRECATED_SINCE(5, 15) /*! \fn Qt::Orientation QWheelEvent::orientation() const \obsolete Use angleDelta() instead. */ +#endif #if QT_CONFIG(wheelevent) #if QT_DEPRECATED_SINCE(5, 15) @@ -929,6 +931,7 @@ QWheelEvent::~QWheelEvent() \endlist */ +#if QT_DEPRECATED_SINCE(5, 15) /*! \fn int QWheelEvent::delta() const \obsolete @@ -992,6 +995,7 @@ QWheelEvent::~QWheelEvent() This function has been deprecated, use globalPosition() instead. */ +#endif /*! \fn Qt::ScrollPhase QWheelEvent::phase() const -- cgit v1.2.3 From ab55046862644441ade0fa1dc4aba98b32796877 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 15 Aug 2019 14:44:27 +0200 Subject: Brush up tst_QGraphicsScene - Fix includes - Add window titles - Introduce nullptr - Remove unneeded C-style casts in QCOMPARE - Replace remaining C-style casts - Use range-based for - Fix static invocation - Fix class structure, add override, use member initialization - Fix top level widget leaks and add a check - Silence debug output by using a logging category - Use Qt 5 connection syntax Task-number: QTBUG-76497 Change-Id: I77532a517353d04d1da43ce844988ee0ac2ffc7d Reviewed-by: Oliver Wolff --- .../qgraphicsscene/tst_qgraphicsscene.cpp | 669 +++++++++++---------- 1 file changed, 354 insertions(+), 315 deletions(-) diff --git a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp index 46f1d5df5c..cc6ed2f80e 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -26,11 +26,24 @@ ** ****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include #include -#include -#include +#include +#include + #include #include #include @@ -39,7 +52,7 @@ #include #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) -#include +#include #define Q_CHECK_PAINTEVENTS \ if (::SwitchDesktop(::GetThreadDesktop(::GetCurrentThreadId())) == 0) \ QSKIP("The Graphics View doesn't get the paint events"); @@ -51,6 +64,7 @@ Q_DECLARE_METATYPE(Qt::FocusReason) Q_DECLARE_METATYPE(QPainterPath) Q_DECLARE_METATYPE(Qt::AspectRatioMode) Q_DECLARE_METATYPE(Qt::ItemSelectionMode) +Q_DECLARE_METATYPE(QGraphicsItem::GraphicsItemFlags) static const int randomX[] = {276, 40, 250, 864, -56, 426, 855, 825, 184, 955, -798, -804, 773, 282, 489, 686, 780, -220, 50, 749, -856, -205, 81, 492, -819, 518, @@ -95,14 +109,16 @@ static const int randomY[] = {603, 70, -318, 843, 450, -637, 199, -527, 407, 964 -588, 864, 234, 225, -303, 493, 246, 153, 338, -378, 377, -819, 140, 136, 467, -849, -326, -533, 166, 252, -994, -699, 904, -566, 621, -752}; +Q_LOGGING_CATEGORY(lcTests, "qt.widgets.tests") + class HoverItem : public QGraphicsRectItem { public: HoverItem() - : QGraphicsRectItem(QRectF(-10, -10, 20, 20)), isHovered(false) + : QGraphicsRectItem(QRectF(-10, -10, 20, 20)) { setAcceptHoverEvents(true); } - bool isHovered; + bool isHovered = false; protected: void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) @@ -128,13 +144,13 @@ class EventSpy : public QGraphicsWidget Q_OBJECT public: EventSpy(QObject *watched, QEvent::Type type) - : _count(0), spied(type) + : spied(type) { watched->installEventFilter(this); } EventSpy(QGraphicsScene *scene, QGraphicsItem *watched, QEvent::Type type) - : _count(0), spied(type) + : spied(type) { scene->addItem(this); watched->installSceneEventFilter(this); @@ -143,7 +159,7 @@ public: int count() const { return _count; } protected: - bool eventFilter(QObject *watched, QEvent *event) + bool eventFilter(QObject *watched, QEvent *event) override { Q_UNUSED(watched); if (event->type() == spied) @@ -151,7 +167,7 @@ protected: return false; } - bool sceneEventFilter(QGraphicsItem *watched, QEvent *event) + bool sceneEventFilter(QGraphicsItem *watched, QEvent *event) override { Q_UNUSED(watched); if (event->type() == spied) @@ -159,8 +175,8 @@ protected: return false; } - int _count; - QEvent::Type spied; + int _count = 0; + const QEvent::Type spied; }; class tst_QGraphicsScene : public QObject @@ -273,8 +289,10 @@ private slots: void tst_QGraphicsScene::cleanup() { // ensure not even skipped tests with custom input context leave it dangling - QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); - inputMethodPrivate->testContext = 0; + QInputMethodPrivate *inputMethodPrivate = + QInputMethodPrivate::get(QGuiApplication::inputMethod()); + inputMethodPrivate->testContext = nullptr; + QTRY_VERIFY(QApplication::topLevelWidgets().isEmpty()); } void tst_QGraphicsScene::construction() @@ -287,7 +305,7 @@ void tst_QGraphicsScene::construction() QVERIFY(scene.items(QPolygonF()).isEmpty()); QVERIFY(scene.items(QPainterPath()).isEmpty()); QTest::ignoreMessage(QtWarningMsg, "QGraphicsScene::collidingItems: cannot find collisions for null item"); - QVERIFY(scene.collidingItems(0).isEmpty()); + QVERIFY(scene.collidingItems(nullptr).isEmpty()); QVERIFY(scene.items(QPointF()).isEmpty()); QVERIFY(scene.selectedItems().isEmpty()); QVERIFY(!scene.focusItem()); @@ -301,7 +319,7 @@ static inline const QGraphicsItem *itemAt(const QGraphicsScene &scene, qreal x, void tst_QGraphicsScene::sceneRect() { QGraphicsScene scene; - QSignalSpy sceneRectChanged(&scene, SIGNAL(sceneRectChanged(QRectF))); + QSignalSpy sceneRectChanged(&scene, &QGraphicsScene::sceneRectChanged); QCOMPARE(scene.sceneRect(), QRectF()); QCOMPARE(sceneRectChanged.count(), 0); @@ -435,9 +453,9 @@ void tst_QGraphicsScene::items() scene.removeItem(items.at(5)); delete items.at(5); - QVERIFY(!scene.items().contains(0)); + QVERIFY(!scene.items().contains(nullptr)); delete items.at(7); - QVERIFY(!scene.items().contains(0)); + QVERIFY(!scene.items().contains(nullptr)); } { QGraphicsScene scene; @@ -516,7 +534,7 @@ void tst_QGraphicsScene::itemsBoundingRect() QGraphicsScene scene; - foreach (QRectF rect, rects) { + for (const auto &rect : qAsConst(rects)) { QPainterPath path; path.addRect(rect); QGraphicsPathItem *item = scene.addPath(path); @@ -581,7 +599,7 @@ void tst_QGraphicsScene::items_QPointF() int n = 0; QList addedItems; - foreach(QRectF rect, items) { + for (const auto &rect : qAsConst(items)) { QPainterPath path; path.addRect(0, 0, rect.width(), rect.height()); @@ -593,7 +611,8 @@ void tst_QGraphicsScene::items_QPointF() } QList itemIndexes; - foreach (QGraphicsItem *item, scene.items(point)) + const auto &actualItemsAtPoint = scene.items(point); + for (QGraphicsItem *item : actualItemsAtPoint) itemIndexes << addedItems.indexOf(item); QCOMPARE(itemIndexes, itemsAtPoint); @@ -912,12 +931,11 @@ void tst_QGraphicsScene::items_QPainterPath_2() class CustomView : public QGraphicsView { public: - CustomView() : repaints(0) - { } + using QGraphicsView::QGraphicsView; - int repaints; + int repaints = 0; protected: - void paintEvent(QPaintEvent *event) + void paintEvent(QPaintEvent *event) override { ++repaints; QGraphicsView::paintEvent(event); @@ -927,7 +945,7 @@ protected: void tst_QGraphicsScene::selectionChanged() { QGraphicsScene scene(0, 0, 1000, 1000); - QSignalSpy spy(&scene, SIGNAL(selectionChanged())); + QSignalSpy spy(&scene, &QGraphicsScene::selectionChanged); QCOMPARE(spy.count(), 0); QPainterPath path; @@ -997,7 +1015,7 @@ void tst_QGraphicsScene::selectionChanged() void tst_QGraphicsScene::selectionChanged2() { QGraphicsScene scene; - QSignalSpy spy(&scene, SIGNAL(selectionChanged())); + QSignalSpy spy(&scene, &QGraphicsScene::selectionChanged); QGraphicsItem *item1 = scene.addRect(0, 0, 100, 100); QGraphicsItem *item2 = scene.addRect(100, 100, 100, 100); @@ -1009,13 +1027,13 @@ void tst_QGraphicsScene::selectionChanged2() QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress); event.setScenePos(QPointF(50, 50)); event.setButton(Qt::LeftButton); - qApp->sendEvent(&scene, &event); + QCoreApplication::sendEvent(&scene, &event); } { QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease); event.setScenePos(QPointF(50, 50)); event.setButton(Qt::LeftButton); - qApp->sendEvent(&scene, &event); + QCoreApplication::sendEvent(&scene, &event); } QVERIFY(item1->isSelected()); QVERIFY(!item2->isSelected()); @@ -1024,13 +1042,13 @@ void tst_QGraphicsScene::selectionChanged2() QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress); event.setScenePos(QPointF(150, 150)); event.setButton(Qt::LeftButton); - qApp->sendEvent(&scene, &event); + QCoreApplication::sendEvent(&scene, &event); } { QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease); event.setScenePos(QPointF(150, 150)); event.setButton(Qt::LeftButton); - qApp->sendEvent(&scene, &event); + QCoreApplication::sendEvent(&scene, &event); } QVERIFY(!item1->isSelected()); QVERIFY(item2->isSelected()); @@ -1040,7 +1058,7 @@ void tst_QGraphicsScene::selectionChanged2() event.setScenePos(QPointF(50, 50)); event.setButton(Qt::LeftButton); event.setModifiers(Qt::ControlModifier); - qApp->sendEvent(&scene, &event); + QCoreApplication::sendEvent(&scene, &event); } QVERIFY(!item1->isSelected()); QVERIFY(item2->isSelected()); @@ -1049,7 +1067,7 @@ void tst_QGraphicsScene::selectionChanged2() QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease); event.setScenePos(QPointF(50, 50)); event.setButton(Qt::LeftButton); - qApp->sendEvent(&scene, &event); + QCoreApplication::sendEvent(&scene, &event); } QVERIFY(item1->isSelected()); QVERIFY(!item2->isSelected()); @@ -1065,10 +1083,11 @@ void tst_QGraphicsScene::addItem() QGraphicsScene scene; CustomView view; + view.setWindowTitle(QTest::currentTestFunction()); view.setScene(&scene); view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); - qApp->processEvents(); + QCoreApplication::processEvents(); view.repaints = 0; scene.addItem(path); @@ -1115,14 +1134,14 @@ void tst_QGraphicsScene::addEllipse() QCOMPARE(ellipse->pen(), QPen(Qt::red)); QCOMPARE(ellipse->brush(), QBrush(Qt::blue)); QCOMPARE(ellipse->rect(), QRectF(-10, -10, 20, 20)); - QCOMPARE(itemAt(scene, 0, 0), (QGraphicsItem *)ellipse); + QCOMPARE(itemAt(scene, 0, 0), ellipse); QVERIFY(scene.items(QPointF(-10, -10)).isEmpty()); - QCOMPARE(itemAt(scene, -9.9, 0), (QGraphicsItem *)ellipse); + QCOMPARE(itemAt(scene, -9.9, 0), ellipse); QVERIFY(scene.items(QPointF(-10, 10)).isEmpty()); - QCOMPARE(itemAt(scene, 0, -9.9), (QGraphicsItem *)ellipse); - QCOMPARE(itemAt(scene, 0, 9.9), (QGraphicsItem *)ellipse); + QCOMPARE(itemAt(scene, 0, -9.9), ellipse); + QCOMPARE(itemAt(scene, 0, 9.9), ellipse); QVERIFY(scene.items(QPointF(10, -10)).isEmpty()); - QCOMPARE(itemAt(scene, 9.9, 0), (QGraphicsItem *)ellipse); + QCOMPARE(itemAt(scene, 9.9, 0), ellipse); QVERIFY(scene.items(QPointF(10, 10)).isEmpty()); } @@ -1136,15 +1155,15 @@ void tst_QGraphicsScene::addLine() QCOMPARE(line->pos(), QPointF()); QCOMPARE(line->pen(), pen); QCOMPARE(line->line(), QLineF(-10, -10, 20, 20)); - QCOMPARE(itemAt(scene, 0, 0), (QGraphicsItem *)line); - QCOMPARE(itemAt(scene, -10, -10), (QGraphicsItem *)line); + QCOMPARE(itemAt(scene, 0, 0), line); + QCOMPARE(itemAt(scene, -10, -10), line); QVERIFY(scene.items(QPointF(-9.9, 0)).isEmpty()); QVERIFY(scene.items(QPointF(-10, 10)).isEmpty()); QVERIFY(scene.items(QPointF(0, -9.9)).isEmpty()); QVERIFY(scene.items(QPointF(0, 9.9)).isEmpty()); QVERIFY(scene.items(QPointF(10, -10)).isEmpty()); QVERIFY(scene.items(QPointF(9.9, 0)).isEmpty()); - QCOMPARE(itemAt(scene, 10, 10), (QGraphicsItem *)line); + QCOMPARE(itemAt(scene, 10, 10), line); } void tst_QGraphicsScene::addPath() @@ -1162,16 +1181,16 @@ void tst_QGraphicsScene::addPath() path->setPen(QPen(Qt::red, 0)); - QCOMPARE(itemAt(scene, 0, 0), (QGraphicsItem *)path); - QCOMPARE(itemAt(scene, -9.9, 0), (QGraphicsItem *)path); - QCOMPARE(itemAt(scene, 9.9, 0), (QGraphicsItem *)path); - QCOMPARE(itemAt(scene, 0, -9.9), (QGraphicsItem *)path); - QCOMPARE(itemAt(scene, 0, 9.9), (QGraphicsItem *)path); - QCOMPARE(itemAt(scene, 0, 30), (QGraphicsItem *)path); - QCOMPARE(itemAt(scene, -9.9, 30), (QGraphicsItem *)path); - QCOMPARE(itemAt(scene, 9.9, 30), (QGraphicsItem *)path); - QCOMPARE(itemAt(scene, 0, 20.1), (QGraphicsItem *)path); - QCOMPARE(itemAt(scene, 0, 39.9), (QGraphicsItem *)path); + QCOMPARE(itemAt(scene, 0, 0), path); + QCOMPARE(itemAt(scene, -9.9, 0), path); + QCOMPARE(itemAt(scene, 9.9, 0), path); + QCOMPARE(itemAt(scene, 0, -9.9), path); + QCOMPARE(itemAt(scene, 0, 9.9), path); + QCOMPARE(itemAt(scene, 0, 30), path); + QCOMPARE(itemAt(scene, -9.9, 30), path); + QCOMPARE(itemAt(scene, 9.9, 30), path); + QCOMPARE(itemAt(scene, 0, 20.1), path); + QCOMPARE(itemAt(scene, 0, 39.9), path); QVERIFY(scene.items(QPointF(-10, -10)).isEmpty()); QVERIFY(scene.items(QPointF(10, -10)).isEmpty()); QVERIFY(scene.items(QPointF(-10, 10)).isEmpty()); @@ -1193,10 +1212,10 @@ void tst_QGraphicsScene::addPixmap() QCOMPARE(pixmap->pos(), QPointF()); QCOMPARE(pixmap->pixmap(), pix); - QCOMPARE(itemAt(scene, 0, 0), (QGraphicsItem *)pixmap); - QCOMPARE(itemAt(scene, pix.width() - 1, 0), (QGraphicsItem *)pixmap); - QCOMPARE(itemAt(scene, 0, pix.height() - 1), (QGraphicsItem *)pixmap); - QCOMPARE(itemAt(scene, pix.width() - 1, pix.height() - 1), (QGraphicsItem *)pixmap); + QCOMPARE(itemAt(scene, 0, 0), pixmap); + QCOMPARE(itemAt(scene, pix.width() - 1, 0), pixmap); + QCOMPARE(itemAt(scene, 0, pix.height() - 1), pixmap); + QCOMPARE(itemAt(scene, pix.width() - 1, pix.height() - 1), pixmap); QVERIFY(scene.items(QPointF(-1, -1)).isEmpty()); QVERIFY(scene.items(QPointF(pix.width() - 1, -1)).isEmpty()); @@ -1218,14 +1237,14 @@ void tst_QGraphicsScene::addRect() rect->setPen(QPen(Qt::red, 0)); - QCOMPARE(itemAt(scene, 0, 0), (QGraphicsItem *)rect); - QCOMPARE(itemAt(scene, -10, -10), (QGraphicsItem *)rect); - QCOMPARE(itemAt(scene, -9.9, 0), (QGraphicsItem *)rect); + QCOMPARE(itemAt(scene, 0, 0),rect); + QCOMPARE(itemAt(scene, -10, -10), rect); + QCOMPARE(itemAt(scene, -9.9, 0), rect); QVERIFY(scene.items(QPointF(-10, 10)).isEmpty()); - QCOMPARE(itemAt(scene, 0, -9.9), (QGraphicsItem *)rect); - QCOMPARE(itemAt(scene, 0, 9.9), (QGraphicsItem *)rect); + QCOMPARE(itemAt(scene, 0, -9.9), rect); + QCOMPARE(itemAt(scene, 0, 9.9), rect); QVERIFY(scene.items(QPointF(10, -10)).isEmpty()); - QCOMPARE(itemAt(scene, 9.9, 0), (QGraphicsItem *)rect); + QCOMPARE(itemAt(scene, 9.9, 0), rect); QVERIFY(scene.items(QPointF(10, 10)).isEmpty()); } @@ -1271,6 +1290,7 @@ void tst_QGraphicsScene::removeItem() scene.setSceneRect(-50, -50, 100, 100); QGraphicsView view(&scene); + view.setWindowTitle(QTest::currentTestFunction()); view.setFixedSize(150, 150); view.show(); QApplication::setActiveWindow(&view); @@ -1342,7 +1362,7 @@ void tst_QGraphicsScene::focusItem() class FocusItem : public QGraphicsTextItem { protected: - void focusOutEvent(QFocusEvent *) + void focusOutEvent(QFocusEvent *) override { QVERIFY(!scene()->focusItem()); } @@ -1359,14 +1379,14 @@ void tst_QGraphicsScene::focusItemLostFocus() scene.addItem(item); item->setFocus(); - QCOMPARE(scene.focusItem(), (QGraphicsItem *)item); + QCOMPARE(scene.focusItem(), item); item->clearFocus(); } class ClearTestItem : public QGraphicsRectItem { public: - ClearTestItem(QGraphicsItem *parent = 0) : QGraphicsRectItem(parent) {} + using QGraphicsRectItem::QGraphicsRectItem; ~ClearTestItem() { qDeleteAll(items); } QList items; }; @@ -1389,7 +1409,7 @@ void tst_QGraphicsScene::clear() scene.setItemIndexMethod(QGraphicsScene::NoIndex); scene.addItem(firstItem); scene.addItem(secondItem); - QCOMPARE(scene.items().at(0), (QGraphicsItem*)firstItem); + QCOMPARE(scene.items().at(0), firstItem); QCOMPARE(scene.items().at(1), secondItem); ClearTestItem *thirdItem = new ClearTestItem(firstItem); @@ -1441,7 +1461,7 @@ void tst_QGraphicsScene::setFocusItem() QVERIFY(item->hasFocus()); QVERIFY(!item2->hasFocus()); - scene.setFocusItem(0); + scene.setFocusItem(nullptr); QVERIFY(!item->hasFocus()); QVERIFY(!item2->hasFocus()); @@ -1562,26 +1582,26 @@ void tst_QGraphicsScene::hoverEvents_siblings() Q_CHECK_PAINTEVENTS QGraphicsScene scene; - QGraphicsItem *lastItem = 0; + QGraphicsItem *lastItem = nullptr; QList items; for (int i = 0; i < 15; ++i) { - QGraphicsItem *item = new HoverItem; + auto item = new HoverItem; scene.addItem(item); - items << (HoverItem *)item; - if (lastItem) { + items << item; + if (lastItem) item->setPos(lastItem->pos() + QPointF(sin(i / 3.0) * 17, cos(i / 3.0) * 17)); - } item->setZValue(i); lastItem = item; } QGraphicsView view(&scene); + view.setWindowTitle(QTest::currentTestFunction()); view.setRenderHint(QPainter::Antialiasing, true); view.setMinimumSize(400, 300); view.rotate(10); view.scale(1.7, 1.7); view.show(); - qApp->setActiveWindow(&view); + QApplication::setActiveWindow(&view); view.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&view)); @@ -1604,8 +1624,8 @@ void tst_QGraphicsScene::hoverEvents_siblings() mouseEvent.setScenePos(items.at(i)->mapToScene(0, 0)); QApplication::sendEvent(&scene, &mouseEvent); - qApp->processEvents(); // this posts updates from the scene to the view - qApp->processEvents(); // which trigger a repaint here + QCoreApplication::processEvents(); // this posts updates from the scene to the view + QCoreApplication::processEvents(); // which trigger a repaint here QTRY_VERIFY(items.at(i)->isHovered); if (j && i > 0) @@ -1621,8 +1641,8 @@ void tst_QGraphicsScene::hoverEvents_siblings() mouseEvent.setScenePos(QPointF(-1000, -1000)); QApplication::sendEvent(&scene, &mouseEvent); - qApp->processEvents(); // this posts updates from the scene to the view - qApp->processEvents(); // which trigger a repaint here + QCoreApplication::processEvents(); // this posts updates from the scene to the view + QCoreApplication::processEvents(); // which trigger a repaint here } } @@ -1631,12 +1651,12 @@ void tst_QGraphicsScene::hoverEvents_parentChild() Q_CHECK_PAINTEVENTS QGraphicsScene scene; - QGraphicsItem *lastItem = 0; + QGraphicsItem *lastItem = nullptr; QList items; for (int i = 0; i < 15; ++i) { - QGraphicsItem *item = new HoverItem; + auto item = new HoverItem; scene.addItem(item); - items << (HoverItem *)item; + items << item; if (lastItem) { item->setParentItem(lastItem); item->setPos(sin(i / 3.0) * 17, cos(i / 3.0) * 17); @@ -1645,12 +1665,13 @@ void tst_QGraphicsScene::hoverEvents_parentChild() } QGraphicsView view(&scene); + view.setWindowTitle(QTest::currentTestFunction()); view.setRenderHint(QPainter::Antialiasing, true); view.setMinimumSize(400, 300); view.rotate(10); view.scale(1.7, 1.7); view.show(); - qApp->setActiveWindow(&view); + QApplication::setActiveWindow(&view); QVERIFY(QTest::qWaitForWindowActive(&view)); QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove); @@ -1669,8 +1690,8 @@ void tst_QGraphicsScene::hoverEvents_parentChild() mouseEvent.setScenePos(items.at(i)->mapToScene(0, 0)); QApplication::sendEvent(&scene, &mouseEvent); - qApp->processEvents(); // this posts updates from the scene to the view - qApp->processEvents(); // which trigger a repaint here + QCoreApplication::processEvents(); // this posts updates from the scene to the view + QCoreApplication::processEvents(); // which trigger a repaint here QTRY_VERIFY(items.at(i)->isHovered); if (i < 14) @@ -1683,8 +1704,8 @@ void tst_QGraphicsScene::hoverEvents_parentChild() mouseEvent.setScenePos(QPointF(-1000, -1000)); QApplication::sendEvent(&scene, &mouseEvent); - qApp->processEvents(); // this posts updates from the scene to the view - qApp->processEvents(); // which trigger a repaint here + QCoreApplication::processEvents(); // this posts updates from the scene to the view + QCoreApplication::processEvents(); // which trigger a repaint here } } @@ -1712,23 +1733,23 @@ void tst_QGraphicsScene::createItemGroup() // All items in children1 are children of parent1 QGraphicsItem *parent1 = scene.addRect(QRectF(-10, -10, 20, 20)); - foreach (QGraphicsItem *item, children1) + for (QGraphicsItem *item : qAsConst(children1)) item->setParentItem(parent1); QGraphicsItemGroup *group = scene.createItemGroup(children1); QCOMPARE(group->parentItem(), parent1); - QCOMPARE(children1.first()->parentItem(), (QGraphicsItem *)group); + QCOMPARE(children1.first()->parentItem(), group); scene.destroyItemGroup(group); QCOMPARE(children1.first()->parentItem(), parent1); group = scene.createItemGroup(children1); QCOMPARE(group->parentItem(), parent1); - QCOMPARE(children1.first()->parentItem(), (QGraphicsItem *)group); + QCOMPARE(children1.first()->parentItem(), group); scene.destroyItemGroup(group); QCOMPARE(children1.first()->parentItem(), parent1); // All items in children2 are children of parent2 QGraphicsItem *parent2 = scene.addRect(QRectF(-10, -10, 20, 20)); - foreach (QGraphicsItem *item, children2) + for (QGraphicsItem *item : qAsConst(children2)) item->setParentItem(parent2); // Now make parent2 a child of parent1, so all children2 are also children @@ -1738,21 +1759,21 @@ void tst_QGraphicsScene::createItemGroup() // The children2 group should still have parent2 as their common ancestor. group = scene.createItemGroup(children2); QCOMPARE(group->parentItem(), parent2); - QCOMPARE(children2.first()->parentItem(), (QGraphicsItem *)group); + QCOMPARE(children2.first()->parentItem(), group); scene.destroyItemGroup(group); QCOMPARE(children2.first()->parentItem(), parent2); // But the set of both children2 and children1 share only parent1. group = scene.createItemGroup(children2 + children1); QCOMPARE(group->parentItem(), parent1); - QCOMPARE(children1.first()->parentItem(), (QGraphicsItem *)group); - QCOMPARE(children2.first()->parentItem(), (QGraphicsItem *)group); + QCOMPARE(children1.first()->parentItem(), group); + QCOMPARE(children2.first()->parentItem(), group); scene.destroyItemGroup(group); QCOMPARE(children1.first()->parentItem(), parent1); QCOMPARE(children2.first()->parentItem(), parent1); // Fixup the parent-child chain - foreach (QGraphicsItem *item, children2) + for (QGraphicsItem *item : qAsConst(children2)) item->setParentItem(parent2); // These share no common parent @@ -1762,7 +1783,7 @@ void tst_QGraphicsScene::createItemGroup() // Make children3 children of parent3 QGraphicsItem *parent3 = scene.addRect(QRectF(-10, -10, 20, 20)); - foreach (QGraphicsItem *item, children3) + for (QGraphicsItem *item : qAsConst(children3)) item->setParentItem(parent3); // These should have parent3 as a parent @@ -1794,15 +1815,14 @@ void tst_QGraphicsScene::createItemGroup() class EventTester : public QGraphicsEllipseItem { public: - EventTester() - : QGraphicsEllipseItem(QRectF(-10, -10, 20, 20)), ignoreMouse(false) + EventTester() : QGraphicsEllipseItem(QRectF(-10, -10, 20, 20)) { } - bool ignoreMouse; - QList eventTypes; + bool ignoreMouse = false; + QVector eventTypes; protected: - bool sceneEvent(QEvent *event) + bool sceneEvent(QEvent *event) override { eventTypes << QEvent::Type(event->type()); switch (event->type()) { @@ -1813,6 +1833,7 @@ protected: event->ignore(); return true; } + break; default: break; } @@ -1867,7 +1888,7 @@ void tst_QGraphicsScene::mouseEventPropagation() QCOMPARE(c->eventTypes.size(), 0); QCOMPARE(b->eventTypes.size(), 0); QCOMPARE(a->eventTypes.size(), 0); - QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)d); + QCOMPARE(scene.mouseGrabberItem(), d); // Send a move QApplication::sendEvent(&scene, &moveEvent); @@ -1876,7 +1897,7 @@ void tst_QGraphicsScene::mouseEventPropagation() QCOMPARE(c->eventTypes.size(), 0); QCOMPARE(b->eventTypes.size(), 0); QCOMPARE(a->eventTypes.size(), 0); - QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)d); + QCOMPARE(scene.mouseGrabberItem(), d); // Send a release QApplication::sendEvent(&scene, &releaseEvent); @@ -1898,7 +1919,7 @@ void tst_QGraphicsScene::mouseEventPropagation() QCOMPARE(c->eventTypes.at(1), QEvent::GraphicsSceneMousePress); QCOMPARE(b->eventTypes.size(), 0); QCOMPARE(a->eventTypes.size(), 0); - QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)c); + QCOMPARE(scene.mouseGrabberItem(), c); // Send another press, with a button that isn't actually accepted QApplication::sendEvent(&scene, &pressEvent); @@ -1908,7 +1929,7 @@ void tst_QGraphicsScene::mouseEventPropagation() QCOMPARE(c->eventTypes.at(2), QEvent::GraphicsSceneMousePress); QCOMPARE(b->eventTypes.size(), 0); QCOMPARE(a->eventTypes.size(), 0); - QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)c); + QCOMPARE(scene.mouseGrabberItem(), c); // Send a move QApplication::sendEvent(&scene, &moveEvent); @@ -1917,7 +1938,7 @@ void tst_QGraphicsScene::mouseEventPropagation() QCOMPARE(c->eventTypes.at(3), QEvent::GraphicsSceneMouseMove); QCOMPARE(b->eventTypes.size(), 0); QCOMPARE(a->eventTypes.size(), 0); - QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)c); + QCOMPARE(scene.mouseGrabberItem(), c); // Send a release QApplication::sendEvent(&scene, &releaseEvent); @@ -1950,7 +1971,7 @@ void tst_QGraphicsScene::mouseEventPropagation() QCOMPARE(c->eventTypes.at(7), QEvent::GraphicsSceneMousePress); QCOMPARE(b->eventTypes.size(), 0); QCOMPARE(a->eventTypes.size(), 0); - QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)c); + QCOMPARE(scene.mouseGrabberItem(), c); // Clicking outside the items removes the mouse grabber } @@ -1999,7 +2020,7 @@ void tst_QGraphicsScene::mouseEventPropagation_ignore() QCOMPARE(d->eventTypes.at(0), QEvent::GrabMouse); QCOMPARE(d->eventTypes.at(1), QEvent::GraphicsSceneMousePress); QCOMPARE(d->eventTypes.at(2), QEvent::UngrabMouse); - QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)a); + QCOMPARE(scene.mouseGrabberItem(), a); a->ignoreMouse = true; @@ -2115,7 +2136,7 @@ public: QVector mouseMovePoints; protected: - void mouseMoveEvent(QGraphicsSceneMouseEvent *event) + void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override { mouseMovePoints << event->scenePos(); } @@ -2140,22 +2161,17 @@ void tst_QGraphicsScene::mouseEventPropagation_mouseMove() class DndTester : public QGraphicsEllipseItem { public: - DndTester(const QRectF &rect) - : QGraphicsEllipseItem(rect), lastEvent(0), - ignoresDragEnter(false), ignoresDragMove(false) - - { - } + using QGraphicsEllipseItem::QGraphicsEllipseItem; ~DndTester() { delete lastEvent; } - QGraphicsSceneDragDropEvent *lastEvent; + QGraphicsSceneDragDropEvent *lastEvent = nullptr; QList eventList; - bool ignoresDragEnter; - bool ignoresDragMove; + bool ignoresDragEnter = false; + bool ignoresDragMove = false; protected: void dragEnterEvent(QGraphicsSceneDragDropEvent *event) @@ -2218,21 +2234,21 @@ void tst_QGraphicsScene::dragAndDrop_simple() QMimeData mimeData; // Initial drag enter for the scene - QDragEnterEvent dragEnter(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragEnterEvent dragEnter(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragEnter); QVERIFY(dragEnter.isAccepted()); QCOMPARE(dragEnter.dropAction(), Qt::CopyAction); { // Move outside the item - QDragMoveEvent dragMove(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(!dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::CopyAction); } { // Move inside the item without setAcceptDrops - QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(!dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::CopyAction); @@ -2241,7 +2257,7 @@ void tst_QGraphicsScene::dragAndDrop_simple() item->setAcceptDrops(true); { // Move inside the item with setAcceptDrops - QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::IgnoreAction); @@ -2255,7 +2271,7 @@ void tst_QGraphicsScene::dragAndDrop_simple() } { // Another move inside the item - QDragMoveEvent dragMove(view.mapFromScene(item->mapToScene(5, 5)), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(item->mapToScene(5, 5)), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::IgnoreAction); @@ -2268,7 +2284,7 @@ void tst_QGraphicsScene::dragAndDrop_simple() } { // Move outside the item - QDragMoveEvent dragMove(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(!dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::CopyAction); @@ -2281,7 +2297,7 @@ void tst_QGraphicsScene::dragAndDrop_simple() } { // Move inside the item again - QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::IgnoreAction); @@ -2295,7 +2311,7 @@ void tst_QGraphicsScene::dragAndDrop_simple() } { // Drop inside the item - QDropEvent drop(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDropEvent drop(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &drop); QVERIFY(drop.isAccepted()); QCOMPARE(drop.dropAction(), Qt::CopyAction); @@ -2322,13 +2338,13 @@ void tst_QGraphicsScene::dragAndDrop_disabledOrInvisible() QMimeData mimeData; // Initial drag enter for the scene - QDragEnterEvent dragEnter(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragEnterEvent dragEnter(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragEnter); QVERIFY(dragEnter.isAccepted()); QCOMPARE(dragEnter.dropAction(), Qt::CopyAction); { // Move inside the item - QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::IgnoreAction); @@ -2338,7 +2354,7 @@ void tst_QGraphicsScene::dragAndDrop_disabledOrInvisible() } { // Move outside the item - QDragMoveEvent dragMove(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(!dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::CopyAction); @@ -2353,7 +2369,7 @@ void tst_QGraphicsScene::dragAndDrop_disabledOrInvisible() { // Move inside the item - QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(!dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::CopyAction); @@ -2369,7 +2385,7 @@ void tst_QGraphicsScene::dragAndDrop_disabledOrInvisible() { // Move inside the item - QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(item->scenePos()), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(!dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::CopyAction); @@ -2378,7 +2394,7 @@ void tst_QGraphicsScene::dragAndDrop_disabledOrInvisible() } // Dummy drop event to keep the Mac from crashing. - QDropEvent dropEvent(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDropEvent dropEvent(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dropEvent); } @@ -2405,14 +2421,14 @@ void tst_QGraphicsScene::dragAndDrop_propagate() QMimeData mimeData; // Initial drag enter for the scene - QDragEnterEvent dragEnter(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragEnterEvent dragEnter(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragEnter); QVERIFY(dragEnter.isAccepted()); QCOMPARE(dragEnter.dropAction(), Qt::CopyAction); { // Move outside the items - QDragMoveEvent dragMove(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(!dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::CopyAction); @@ -2421,7 +2437,7 @@ void tst_QGraphicsScene::dragAndDrop_propagate() } { // Move inside item1 - QDragMoveEvent dragMove(view.mapFromScene(-5, -5), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(-5, -5), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::IgnoreAction); @@ -2432,7 +2448,7 @@ void tst_QGraphicsScene::dragAndDrop_propagate() { // Move into the intersection item1-item2 - QDragMoveEvent dragMove(view.mapFromScene(5, 5), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(5, 5), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(!dragMove.isAccepted()); // move does not propagate, (ignoresDragMove = true) QCOMPARE(item1->eventList.size(), 3); @@ -2443,7 +2459,7 @@ void tst_QGraphicsScene::dragAndDrop_propagate() } { // Move into the item2 - QDragMoveEvent dragMove(view.mapFromScene(15, 15), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(15, 15), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(!dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::CopyAction); @@ -2453,7 +2469,7 @@ void tst_QGraphicsScene::dragAndDrop_propagate() } { // Move inside item1 - QDragMoveEvent dragMove(view.mapFromScene(-5, -5), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(-5, -5), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(dragMove.isAccepted()); QCOMPARE(dragMove.dropAction(), Qt::IgnoreAction); @@ -2467,7 +2483,7 @@ void tst_QGraphicsScene::dragAndDrop_propagate() { item2->ignoresDragEnter = true; // Move into the intersection item1-item2 - QDragMoveEvent dragMove(view.mapFromScene(5, 5), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDragMoveEvent dragMove(view.mapFromScene(5, 5), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dragMove); QVERIFY(dragMove.isAccepted()); // dragEnter propagates down to item1, which then accepts the move event. QCOMPARE(dragMove.dropAction(), Qt::IgnoreAction); @@ -2480,7 +2496,7 @@ void tst_QGraphicsScene::dragAndDrop_propagate() { item2->ignoresDragEnter = false; // Drop on the intersection item1-item2 - QDropEvent drop(view.mapFromScene(5, 5), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDropEvent drop(view.mapFromScene(5, 5), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &drop); QVERIFY(drop.isAccepted()); QCOMPARE(drop.dropAction(), Qt::CopyAction); @@ -2491,7 +2507,7 @@ void tst_QGraphicsScene::dragAndDrop_propagate() } // Dummy drop event to keep the Mac from crashing. - QDropEvent dropEvent(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, 0); + QDropEvent dropEvent(QPoint(0, 0), Qt::CopyAction, &mimeData, Qt::LeftButton, {}); QApplication::sendEvent(view.viewport(), &dropEvent); } #endif @@ -2580,6 +2596,7 @@ void tst_QGraphicsScene::render() pix.fill(Qt::blue); QGraphicsView view; + view.setWindowTitle(QTest::currentTestFunction()); QGraphicsScene scene(&view); scene.addEllipse(QRectF(-10, -10, 20, 20), QPen(Qt::black, 0), QBrush(Qt::white)); scene.addEllipse(QRectF(-2, -7, 4, 4), QPen(Qt::black, 0), QBrush(Qt::yellow))->setZValue(1); @@ -2642,6 +2659,7 @@ void tst_QGraphicsScene::render() gridLayout->addWidget(newLabel, 2, 0); QWidget widget; + widget.setWindowTitle(QTest::currentTestFunction()); widget.setLayout(gridLayout); widget.show(); @@ -2676,6 +2694,7 @@ void tst_QGraphicsScene::renderItemsWithNegativeWidthOrHeight() scene.addItem(item2); QGraphicsView view(&scene); + view.setWindowTitle(QTest::currentTestFunction()); view.setFrameStyle(QFrame::NoFrame); view.resize(150, 150); view.show(); @@ -2710,6 +2729,7 @@ void tst_QGraphicsScene::contextMenuEvent() QVERIFY(scene.hasFocus()); QGraphicsView view(&scene); + view.setWindowTitle(QTest::currentTestFunction()); view.show(); view.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&view)); @@ -2730,7 +2750,7 @@ public: { setBrush(Qt::red); } protected: - void contextMenuEvent(QGraphicsSceneContextMenuEvent *) + void contextMenuEvent(QGraphicsSceneContextMenuEvent *) override { /* just accept */ } }; @@ -2746,6 +2766,7 @@ void tst_QGraphicsScene::contextMenuEvent_ItemIgnoresTransformations() scene.addItem(item); QWidget topLevel; + topLevel.setWindowTitle(QTest::currentTestFunction()); QGraphicsView view(&scene, &topLevel); view.resize(200, 200); topLevel.show(); @@ -2790,14 +2811,14 @@ void tst_QGraphicsScene::update() QGraphicsRectItem *rect = new QGraphicsRectItem(0, 0, 100, 100); rect->setPen(QPen(Qt::black, 0)); scene.addItem(rect); - qApp->processEvents(); + QCoreApplication::processEvents(); rect->setPos(-100, -100); // This function forces indexing itemAt(scene, 0, 0); qRegisterMetaType >("QList"); - QSignalSpy spy(&scene, SIGNAL(changed(QList))); + QSignalSpy spy(&scene, &QGraphicsScene::changed); // We update the scene. scene.update(); @@ -2806,12 +2827,13 @@ void tst_QGraphicsScene::update() itemAt(scene, 0, 0); // This will process the pending update - QApplication::instance()->processEvents(); + QCoreApplication::processEvents(); // Check that the update region is correct QCOMPARE(spy.count(), 1); QRectF region; - foreach (QRectF rectF, qvariant_cast >(spy.at(0).at(0))) + const auto &rects = qvariant_cast >(spy.at(0).at(0)); + for (const auto &rectF : rects) region |= rectF; QCOMPARE(region, QRectF(-100, -100, 200, 200)); } @@ -2821,9 +2843,10 @@ void tst_QGraphicsScene::update2() QGraphicsScene scene; scene.setSceneRect(-200, -200, 200, 200); CustomView view; + view.setWindowTitle(QTest::currentTestFunction()); view.setScene(&scene); view.show(); - qApp->setActiveWindow(&view); + QApplication::setActiveWindow(&view); QVERIFY(QTest::qWaitForWindowActive(&view)); QTRY_VERIFY(view.repaints >= 1); view.repaints = 0; @@ -2831,13 +2854,13 @@ void tst_QGraphicsScene::update2() // Make sure QGraphicsScene::update only requires one event-loop iteration // before the view is updated. scene.update(); - qApp->processEvents(); + QCoreApplication::processEvents(); QTRY_COMPARE(view.repaints, 1); view.repaints = 0; // The same for partial scene updates. scene.update(QRectF(-100, -100, 100, 100)); - qApp->processEvents(); + QCoreApplication::processEvents(); QCOMPARE(view.repaints, 1); } @@ -2853,7 +2876,7 @@ void tst_QGraphicsScene::views() QCOMPARE(scene.views().size(), 2); QVERIFY(scene.views().contains(&view1)); - view.setScene(0); + view.setScene(nullptr); QCOMPARE(scene.views().size(), 1); QCOMPARE(scene.views().at(0), &view1); @@ -2871,12 +2894,12 @@ void tst_QGraphicsScene::views() class CustomScene : public QGraphicsScene { public: - CustomScene() : gotTimerEvent(false) + CustomScene() { startTimer(10); } - bool gotTimerEvent; + bool gotTimerEvent = false; protected: - void timerEvent(QTimerEvent *) + void timerEvent(QTimerEvent *) override { gotTimerEvent = true; } @@ -2893,7 +2916,7 @@ void tst_QGraphicsScene::testEvent() class DisabledItemTester : public QGraphicsRectItem { public: - DisabledItemTester(const QRectF &rect, QGraphicsItem *parent = 0) + DisabledItemTester(const QRectF &rect, QGraphicsItem *parent = nullptr) : QGraphicsRectItem(rect, parent) { } @@ -2901,13 +2924,13 @@ public: QList receivedSceneEventFilters; protected: - bool sceneEventFilter(QGraphicsItem *watched, QEvent *event) + bool sceneEventFilter(QGraphicsItem *watched, QEvent *event) override { receivedSceneEventFilters << event->type(); return QGraphicsRectItem::sceneEventFilter(watched, event); } - bool sceneEvent(QEvent *event) + bool sceneEvent(QEvent *event) override { receivedSceneEvents << event->type(); return QGraphicsRectItem::sceneEvent(event); @@ -2965,11 +2988,9 @@ void tst_QGraphicsScene::eventsToDisabledItems() class ExposedPixmapItem : public QGraphicsPixmapItem { public: - ExposedPixmapItem(QGraphicsItem *item = 0) - : QGraphicsPixmapItem(item) - { } + using QGraphicsPixmapItem::QGraphicsPixmapItem; - void paint(QPainter *, const QStyleOptionGraphicsItem *option, QWidget *) + void paint(QPainter *, const QStyleOptionGraphicsItem *option, QWidget *) override { exposed = option->exposedRect; } @@ -3013,8 +3034,9 @@ void tst_QGraphicsScene::tabFocus_emptyScene() QWidget widget; widget.setLayout(layout); + widget.setWindowTitle(QTest::currentTestFunction()); widget.show(); - qApp->setActiveWindow(&widget); + QApplication::setActiveWindow(&widget); widget.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&widget)); @@ -3060,9 +3082,10 @@ void tst_QGraphicsScene::tabFocus_sceneWithFocusableItems() layout->addWidget(dial2); QWidget widget; + widget.setWindowTitle(QTest::currentTestFunction()); widget.setLayout(layout); widget.show(); - qApp->setActiveWindow(&widget); + QApplication::setActiveWindow(&widget); widget.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&widget)); @@ -3112,18 +3135,18 @@ void tst_QGraphicsScene::tabFocus_sceneWithFocusableItems() QVERIFY(!view->viewport()->hasFocus()); QVERIFY(!scene.hasFocus()); QVERIFY(!item->hasFocus()); - QCOMPARE(scene.focusItem(), static_cast(item)); + QCOMPARE(scene.focusItem(), item); // Check that the correct item regains focus. widget.show(); - qApp->setActiveWindow(&widget); + QApplication::setActiveWindow(&widget); widget.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&widget)); QVERIFY(view->hasFocus()); QTRY_VERIFY(scene.isActive()); QVERIFY(view->viewport()->hasFocus()); QVERIFY(scene.hasFocus()); - QCOMPARE(scene.focusItem(), static_cast(item)); + QCOMPARE(scene.focusItem(), item); QVERIFY(item->hasFocus()); } @@ -3131,14 +3154,13 @@ class FocusWidget : public QGraphicsWidget { Q_OBJECT public: - FocusWidget(QGraphicsItem *parent = 0) - : QGraphicsWidget(parent), tabs(0), backTabs(0) + FocusWidget(QGraphicsItem *parent = nullptr) : QGraphicsWidget(parent) { setFocusPolicy(Qt::StrongFocus); resize(100, 100); } - void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) override { if (option->state & QStyle::State_HasFocus) { painter->fillRect(rect(), Qt::blue); @@ -3152,11 +3174,11 @@ public: } } - int tabs; - int backTabs; + int tabs = 0; + int backTabs = 0; protected: - bool sceneEvent(QEvent *event) + bool sceneEvent(QEvent *event) override { if (event->type() == QEvent::KeyPress) { QKeyEvent *k = static_cast(event); @@ -3168,9 +3190,9 @@ protected: return QGraphicsWidget::sceneEvent(event); } - void focusInEvent(QFocusEvent *) + void focusInEvent(QFocusEvent *) override { update(); } - void focusOutEvent(QFocusEvent *) + void focusOutEvent(QFocusEvent *) override { update(); } }; @@ -3195,9 +3217,10 @@ void tst_QGraphicsScene::tabFocus_sceneWithFocusWidgets() layout->addWidget(dial2); QWidget widget; + widget.setWindowTitle(QTest::currentTestFunction()); widget.setLayout(layout); widget.show(); - qApp->setActiveWindow(&widget); + QApplication::setActiveWindow(&widget); widget.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&widget)); @@ -3236,7 +3259,7 @@ void tst_QGraphicsScene::tabFocus_sceneWithFocusWidgets() widget.hide(); QTest::qWait(15); widget.show(); - qApp->setActiveWindow(&widget); + QApplication::setActiveWindow(&widget); widget.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&widget)); QTRY_VERIFY(widget1->hasFocus()); @@ -3279,9 +3302,10 @@ void tst_QGraphicsScene::tabFocus_sceneWithNestedFocusWidgets() layout->addWidget(dial2); QWidget widget; + widget.setWindowTitle(QTest::currentTestFunction()); widget.setLayout(layout); widget.show(); - qApp->setActiveWindow(&widget); + QApplication::setActiveWindow(&widget); widget.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&widget)); @@ -3366,7 +3390,7 @@ void tst_QGraphicsScene::tabFocus_sceneWithNestedFocusWidgets() widget.hide(); QTest::qWait(12); widget.show(); - qApp->setActiveWindow(&widget); + QApplication::setActiveWindow(&widget); widget.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&widget)); QTRY_VERIFY(widget1->hasFocus()); @@ -3390,11 +3414,11 @@ void tst_QGraphicsScene::style() QCOMPARE(sceneSpy.count(), 1); QCOMPARE(proxySpy.count(), 1); QCOMPARE(editSpy.count(), 1); - QCOMPARE(scene.style(), (QStyle *)windowsStyle); - QCOMPARE(proxy->style(), (QStyle *)windowsStyle); - QCOMPARE(edit->style(), (QStyle *)windowsStyle); + QCOMPARE(scene.style(), windowsStyle.data()); + QCOMPARE(proxy->style(), windowsStyle.data()); + QCOMPARE(edit->style(), windowsStyle.data()); - scene.setStyle(0); + scene.setStyle(nullptr); QCOMPARE(sceneSpy.count(), 2); QCOMPARE(proxySpy.count(), 2); QCOMPARE(editSpy.count(), 2); @@ -3411,11 +3435,12 @@ void tst_QGraphicsScene::task139710_bspTreeCrash() for (int i = 0; i < 2; ++i) { // trigger delayed item indexing - qApp->processEvents(); + QCoreApplication::processEvents(); scene.setSceneRect(0, 0, 10000, 10000); // delete all items in the scene - pointers are now likely to be recycled - foreach (QGraphicsItem *item, scene.items()) { + const auto &items = scene.items(); + for (QGraphicsItem *item : items) { scene.removeItem(item); delete item; } @@ -3427,7 +3452,7 @@ void tst_QGraphicsScene::task139710_bspTreeCrash() } // trigger delayed item indexing for the first 1000 items - qApp->processEvents(); + QCoreApplication::processEvents(); // add 1000 more items - the BSP tree is now resized for (int i = 0; i < 1000; ++i) { @@ -3437,7 +3462,8 @@ void tst_QGraphicsScene::task139710_bspTreeCrash() // get items from the BSP tree and use them. there was junk in the tree // the second time this happened. - foreach (QGraphicsItem *item, scene.items(QRectF(0, 0, 1000, 1000))) + const auto &itemsWithin = scene.items(QRectF(0, 0, 1000, 1000)); + for (QGraphicsItem *item : itemsWithin) item->moveBy(0, 0); } } @@ -3446,7 +3472,7 @@ void tst_QGraphicsScene::task139782_containsItemBoundingRect() { // The item in question has a scene bounding rect of (10, 10, 50, 50) QGraphicsScene scene(0.0, 0.0, 200.0, 200.0); - QGraphicsRectItem *item = new QGraphicsRectItem(0.0, 0.0, 50.0, 50.0, 0); + QGraphicsRectItem *item = new QGraphicsRectItem(0.0, 0.0, 50.0, 50.0, nullptr); scene.addItem(item); item->setPos(10.0, 10.0); @@ -3476,7 +3502,8 @@ void tst_QGraphicsScene::task160653_selectionChanged() QGraphicsScene scene(0, 0, 100, 100); scene.addItem(new QGraphicsRectItem(0, 0, 20, 20)); scene.addItem(new QGraphicsRectItem(30, 30, 20, 20)); - foreach (QGraphicsItem *item, scene.items()) { + const auto &items = scene.items(); + for (QGraphicsItem *item : items) { item->setFlags( item->flags() | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable); item->setSelected(true); @@ -3484,12 +3511,13 @@ void tst_QGraphicsScene::task160653_selectionChanged() QVERIFY(scene.items().size() > 1); QCOMPARE(scene.items().size(), scene.selectedItems().size()); - QSignalSpy spy(&scene, SIGNAL(selectionChanged())); + QSignalSpy spy(&scene, &QGraphicsScene::selectionChanged); QGraphicsView view(&scene); + view.setWindowTitle(QTest::currentTestFunction()); view.show(); QVERIFY(QTest::qWaitForWindowActive(&view)); QTest::mouseClick( - view.viewport(), Qt::LeftButton, 0, view.mapFromScene(scene.items().first()->scenePos())); + view.viewport(), Qt::LeftButton, {}, view.mapFromScene(scene.items().first()->scenePos())); QCOMPARE(spy.count(), 1); } @@ -3574,17 +3602,21 @@ void tst_QGraphicsScene::sorting() scene.addItem(t_1); - foreach (QGraphicsItem *item, scene.items()) + const auto &items = scene.items(); + for (QGraphicsItem *item : items) item->setFlag(QGraphicsItem::ItemIsSelectable); // QGraphicsView view(&scene); // view.setDragMode(QGraphicsView::RubberBandDrag); // view.show(); - qDebug() << "items: {"; - foreach (QGraphicsItem *item, scene.items(QRectF(32, 31, 4, 55))) - qDebug() << "\t" << item->data(0).toString(); - qDebug() << "}"; + if (lcTests().isDebugEnabled()) { + qCDebug(lcTests) << "items: {"; + const auto &itemsWithin = scene.items(QRectF(32, 31, 4, 55)); + for (QGraphicsItem *item : itemsWithin) + qCDebug(lcTests).nospace() << '\t' << item->data(0).toString(); + qCDebug(lcTests) << '}'; + } QCOMPARE(scene.items(QRectF(32, 31, 4, 55)), QList() @@ -3664,11 +3696,11 @@ void tst_QGraphicsScene::changedSignal() QFETCH(bool, withView); QGraphicsScene scene; ChangedListener cl; - connect(&scene, SIGNAL(changed(QList)), &cl, SLOT(changed(QList))); + connect(&scene, &QGraphicsScene::changed, &cl, &ChangedListener::changed); - QGraphicsView *view = 0; + QScopedPointer view; if (withView) - view = new QGraphicsView(&scene); + view.reset(new QGraphicsView(&scene)); QGraphicsRectItem *rect = new QGraphicsRectItem(0, 0, 10, 10); rect->setPen(QPen(Qt::black, 0)); @@ -3682,16 +3714,13 @@ void tst_QGraphicsScene::changedSignal() rect->setPos(20, 0); QCOMPARE(cl.changes.size(), 1); - qApp->processEvents(); + QCoreApplication::processEvents(); QCOMPARE(cl.changes.size(), 2); QCOMPARE(cl.changes.at(1).size(), 2); QCOMPARE(cl.changes.at(1).first(), QRectF(0, 0, 10, 10)); QCOMPARE(cl.changes.at(1).last(), QRectF(20, 0, 10, 10)); QCOMPARE(scene.sceneRect(), QRectF(0, 0, 30, 10)); - - if (withView) - delete view; } void tst_QGraphicsScene::stickyFocus_data() @@ -3718,7 +3747,7 @@ void tst_QGraphicsScene::stickyFocus() QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress); event.setScenePos(QPointF(-10, -10)); // outside item event.setButton(Qt::LeftButton); - qApp->sendEvent(&scene, &event); + QCoreApplication::sendEvent(&scene, &event); QCOMPARE(text->hasFocus(), sticky); } @@ -3736,43 +3765,50 @@ void tst_QGraphicsScene::sendEvent() void tst_QGraphicsScene::inputMethod_data() { - QTest::addColumn("flags"); + QTest::addColumn("flags"); QTest::addColumn("callFocusItem"); - QTest::newRow("0") << 0 << false; - QTest::newRow("1") << (int)QGraphicsItem::ItemAcceptsInputMethod << false; - QTest::newRow("2") << (int)QGraphicsItem::ItemIsFocusable << false; + QTest::newRow("0") << QGraphicsItem::GraphicsItemFlags() << false; + QTest::newRow("1") << QGraphicsItem::GraphicsItemFlags(QGraphicsItem::ItemAcceptsInputMethod) << false; + QTest::newRow("2") << QGraphicsItem::GraphicsItemFlags(QGraphicsItem::ItemIsFocusable) << false; QTest::newRow("3") << - (int)(QGraphicsItem::ItemAcceptsInputMethod|QGraphicsItem::ItemIsFocusable) << true; + (QGraphicsItem::ItemAcceptsInputMethod|QGraphicsItem::ItemIsFocusable) << true; } class InputMethodTester : public QGraphicsRectItem { - void inputMethodEvent(QInputMethodEvent *) { ++eventCalls; } - QVariant inputMethodQuery(Qt::InputMethodQuery) const { ++queryCalls; return QVariant(); } + void inputMethodEvent(QInputMethodEvent *) override { ++eventCalls; } + QVariant inputMethodQuery(Qt::InputMethodQuery) const override + { + ++queryCalls; + return QVariant(); + } + public: - int eventCalls; - mutable int queryCalls; + int eventCalls = 0; + mutable int queryCalls = 0; }; void tst_QGraphicsScene::inputMethod() { PlatformInputContext inputContext; - QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); + QInputMethodPrivate *inputMethodPrivate = + QInputMethodPrivate::get(QGuiApplication::inputMethod()); inputMethodPrivate->testContext = &inputContext; - QFETCH(int, flags); + QFETCH(QGraphicsItem::GraphicsItemFlags, flags); QFETCH(bool, callFocusItem); InputMethodTester *item = new InputMethodTester; - item->setFlags((QGraphicsItem::GraphicsItemFlags)flags); + item->setFlags(flags); QGraphicsScene scene; QGraphicsView view(&scene); view.show(); + view.setWindowTitle(QTest::currentTestFunction()); QApplication::setActiveWindow(&view); view.setFocus(); QVERIFY(QTest::qWaitForWindowActive(&view)); - QCOMPARE(QApplication::activeWindow(), static_cast(&view)); + QCOMPARE(QApplication::activeWindow(), &view); inputContext.m_resetCallCount = 0; inputContext.m_commitCallCount = 0; @@ -3784,25 +3820,25 @@ void tst_QGraphicsScene::inputMethod() QCOMPARE(inputContext.m_resetCallCount, 0); item->eventCalls = 0; - qApp->sendEvent(&scene, &event); + QCoreApplication::sendEvent(&scene, &event); QCOMPARE(item->eventCalls, callFocusItem ? 1 : 0); item->queryCalls = 0; - scene.inputMethodQuery((Qt::InputMethodQuery)0); + scene.inputMethodQuery(Qt::InputMethodQuery(0)); QCOMPARE(item->queryCalls, callFocusItem ? 1 : 0); - scene.setFocusItem(0); + scene.setFocusItem(nullptr); // the input context is reset twice, once because an item has lost focus and again because // the Qt::WA_InputMethodEnabled flag is cleared because no item has focus. QCOMPARE(inputContext.m_resetCallCount + inputContext.m_commitCallCount, callFocusItem ? 2 : 0); QCOMPARE(item->queryCalls, callFocusItem ? 1 : 0); // verify that value is unaffected item->eventCalls = 0; - qApp->sendEvent(&scene, &event); + QCoreApplication::sendEvent(&scene, &event); QCOMPARE(item->eventCalls, 0); item->queryCalls = 0; - scene.inputMethodQuery((Qt::InputMethodQuery)0); + scene.inputMethodQuery(Qt::InputMethodQuery(0)); QCOMPARE(item->queryCalls, 0); } @@ -3826,18 +3862,18 @@ void tst_QGraphicsScene::dispatchHoverOnPress() me.setButtons(Qt::LeftButton); QGraphicsSceneMouseEvent me2(QEvent::GraphicsSceneMouseRelease); me2.setButton(Qt::LeftButton); - qApp->sendEvent(&scene, &me); - qApp->sendEvent(&scene, &me2); - QCOMPARE(tester1->eventTypes, QList() + QCoreApplication::sendEvent(&scene, &me); + QCoreApplication::sendEvent(&scene, &me2); + QCOMPARE(tester1->eventTypes, QVector() << QEvent::GraphicsSceneHoverEnter << QEvent::GraphicsSceneHoverMove << QEvent::GrabMouse << QEvent::GraphicsSceneMousePress << QEvent::UngrabMouse); tester1->eventTypes.clear(); - qApp->sendEvent(&scene, &me); - qApp->sendEvent(&scene, &me2); - QCOMPARE(tester1->eventTypes, QList() + QCoreApplication::sendEvent(&scene, &me); + QCoreApplication::sendEvent(&scene, &me2); + QCOMPARE(tester1->eventTypes, QVector() << QEvent::GraphicsSceneHoverMove << QEvent::GrabMouse << QEvent::GraphicsSceneMousePress @@ -3852,21 +3888,21 @@ void tst_QGraphicsScene::dispatchHoverOnPress() me2.setScenePos(QPointF(30, 30)); me2.setButton(Qt::LeftButton); tester1->eventTypes.clear(); - qApp->sendEvent(&scene, &me); - qApp->sendEvent(&scene, &me2); - qDebug() << tester1->eventTypes; - QCOMPARE(tester1->eventTypes, QList() + QCoreApplication::sendEvent(&scene, &me); + QCoreApplication::sendEvent(&scene, &me2); + qCDebug(lcTests) << tester1->eventTypes; + QCOMPARE(tester1->eventTypes, QVector() << QEvent::GraphicsSceneHoverLeave); - QCOMPARE(tester2->eventTypes, QList() + QCOMPARE(tester2->eventTypes, QVector() << QEvent::GraphicsSceneHoverEnter << QEvent::GraphicsSceneHoverMove << QEvent::GrabMouse << QEvent::GraphicsSceneMousePress << QEvent::UngrabMouse); tester2->eventTypes.clear(); - qApp->sendEvent(&scene, &me); - qApp->sendEvent(&scene, &me2); - QCOMPARE(tester2->eventTypes, QList() + QCoreApplication::sendEvent(&scene, &me); + QCoreApplication::sendEvent(&scene, &me2); + QCOMPARE(tester2->eventTypes, QVector() << QEvent::GraphicsSceneHoverMove << QEvent::GrabMouse << QEvent::GraphicsSceneMousePress @@ -3915,7 +3951,7 @@ void tst_QGraphicsScene::initialFocus() if (activeScene) { QEvent windowActivate(QEvent::WindowActivate); - qApp->sendEvent(&scene, &windowActivate); + QCoreApplication::sendEvent(&scene, &windowActivate); scene.setFocus(); } @@ -3923,7 +3959,7 @@ void tst_QGraphicsScene::initialFocus() if (!activeScene) { QEvent windowActivate(QEvent::WindowActivate); - qApp->sendEvent(&scene, &windowActivate); + QCoreApplication::sendEvent(&scene, &windowActivate); scene.setFocus(); } @@ -3933,14 +3969,13 @@ void tst_QGraphicsScene::initialFocus() class PolishItem : public QGraphicsTextItem { public: - PolishItem(QGraphicsItem *parent = 0) - : QGraphicsTextItem(parent), polished(false), deleteChildrenInPolish(true), addChildrenInPolish(false) { } + using QGraphicsTextItem::QGraphicsTextItem; - bool polished; - bool deleteChildrenInPolish; - bool addChildrenInPolish; + bool polished = false; + bool deleteChildrenInPolish = true; + bool addChildrenInPolish = false; protected: - QVariant itemChange(GraphicsItemChange change, const QVariant& value) + QVariant itemChange(GraphicsItemChange change, const QVariant& value) override { if (change == ItemVisibleChange) { polished = true; @@ -3979,19 +4014,19 @@ void tst_QGraphicsScene::polishItems2() // Wait for the polish event to be delivered. QVERIFY(!item->polished); - QApplication::sendPostedEvents(&scene, QEvent::MetaCall); + QCoreApplication::sendPostedEvents(&scene, QEvent::MetaCall); QVERIFY(item->polished); // We deleted the children we added above, but we also // added 10 new children. These should be polished in the next // event loop iteration. - QList children = item->childItems(); + const QList children = item->childItems(); QCOMPARE(children.count(), 10); - foreach (QGraphicsItem *child, children) + for (QGraphicsItem *child : children) QVERIFY(!static_cast(child)->polished); - QApplication::sendPostedEvents(&scene, QEvent::MetaCall); - foreach (QGraphicsItem *child, children) + QCoreApplication::sendPostedEvents(&scene, QEvent::MetaCall); + for (QGraphicsItem *child : children) QVERIFY(static_cast(child)->polished); } @@ -4008,6 +4043,7 @@ void tst_QGraphicsScene::isActive() { QWidget toplevel1; + toplevel1.setWindowTitle(QTest::currentTestFunction()); QHBoxLayout *layout = new QHBoxLayout; toplevel1.setLayout(layout); QGraphicsView *view1 = new QGraphicsView(&scene1); @@ -4075,6 +4111,7 @@ void tst_QGraphicsScene::isActive() { const QRect availableGeometry = QGuiApplication::primaryScreen()->availableGeometry(); QWidget toplevel2; + toplevel2.setWindowTitle(QTest::currentTestFunction()); QHBoxLayout *layout = new QHBoxLayout; toplevel2.setLayout(layout); QGraphicsView *view1 = new QGraphicsView(&scene1); @@ -4141,7 +4178,7 @@ void tst_QGraphicsScene::isActive() QApplication::setActiveWindow(&topLevelView); topLevelView.setFocus(); QVERIFY(QTest::qWaitForWindowActive(&topLevelView)); - QCOMPARE(QApplication::activeWindow(), static_cast(&topLevelView)); + QCOMPARE(QApplication::activeWindow(), &topLevelView); QVERIFY(!scene1.isActive()); QVERIFY(!scene2.isActive()); @@ -4211,7 +4248,7 @@ void tst_QGraphicsScene::isActive() QVERIFY(scene1.hasFocus()); QVERIFY(!scene2.hasFocus()); - view1->setParent(0); + view1->setParent(nullptr); QVERIFY(!scene1.isActive()); QVERIFY(scene2.isActive()); QVERIFY(!scene1.hasFocus()); @@ -4243,7 +4280,7 @@ void tst_QGraphicsScene::siblingIndexAlwaysValid() scene.addItem(parent2); //Then we make the child a top level - child->setParentItem(0); + child->setParentItem(nullptr); //This is trigerred by a repaint... QGraphicsScenePrivate::get(&scene)->index->estimateTopLevelItems(QRectF(), Qt::AscendingOrder); @@ -4259,6 +4296,7 @@ void tst_QGraphicsScene::siblingIndexAlwaysValid() scene2.setItemIndexMethod(QGraphicsScene::NoIndex); QGraphicsView view2(&scene2); + view2.setWindowTitle(QTest::currentTestFunction()); // first add the blue rect QGraphicsRectItem* const item1 = new QGraphicsRectItem(QRect( 10, 10, 10, 10 )); @@ -4302,9 +4340,10 @@ void tst_QGraphicsScene::removeFullyTransparentItem() child->setParentItem(parent); CustomView view; + view.setWindowTitle(QTest::currentTestFunction()); view.setScene(&scene); view.show(); - qApp->setActiveWindow(&view); + QApplication::setActiveWindow(&view); QVERIFY(QTest::qWaitForWindowActive(&view)); QCoreApplication::processEvents(); // Process all queued paint events @@ -4353,33 +4392,34 @@ void tst_QGraphicsScene::taskQTBUG_5904_crashWithDeviceCoordinateCache() void tst_QGraphicsScene::taskQT657_paintIntoCacheWithTransparentParts() { // Test using DeviceCoordinateCache and opaque item - QWidget *w = new QWidget(); + QScopedPointer w(new QWidget); w->setPalette(QColor(0, 0, 255)); w->setGeometry(0, 0, 50, 50); QGraphicsScene *scene = new QGraphicsScene(); - CustomView *view = new CustomView; - view->setScene(scene); + CustomView view; + view.setWindowTitle(QTest::currentTestFunction()); + view.setScene(scene); - QGraphicsProxyWidget *proxy = scene->addWidget(w); + QGraphicsProxyWidget *proxy = scene->addWidget(w.data()); proxy->setCacheMode(QGraphicsItem::DeviceCoordinateCache); proxy->setTransform(QTransform().rotate(15), true); - view->show(); - QVERIFY(QTest::qWaitForWindowExposed(view)); - view->repaints = 0; + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + view.repaints = 0; proxy->update(10, 10, 10, 10); - QTRY_VERIFY(view->repaints > 0); + QTRY_VERIFY(view.repaints > 0); QPixmap pix; QGraphicsItemPrivate* itemp = QGraphicsItemPrivate::get(proxy); - QTRY_VERIFY(QPixmapCache::find(itemp->extraItemCache()->deviceData.value(view->viewport()).key, &pix)); + QTRY_VERIFY(QPixmapCache::find(itemp->extraItemCache()->deviceData.value(view.viewport()).key, &pix)); QTransform t = proxy->sceneTransform(); // Map from scene coordinates to pixmap coordinates. // X origin in the pixmap is the most-left point // of the item's boundingRect in the scene. - qreal adjust = t.mapRect(proxy->boundingRect().toRect()).left(); + const int adjust = t.mapRect(proxy->boundingRect().toRect()).left(); QRect rect = t.mapRect(QRect(10, 10, 10, 10)).adjusted(-adjust, 0, -adjust + 1, 1); QPixmap subpix = pix.copy(rect); @@ -4388,8 +4428,6 @@ void tst_QGraphicsScene::taskQT657_paintIntoCacheWithTransparentParts() for(int j = 0; j < im.height(); j++) QCOMPARE(qAlpha(im.pixel(i, j)), 255); } - - delete w; } void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() @@ -4403,28 +4441,29 @@ void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() rectItem->setParentItem(backItem); QGraphicsScene *scene = new QGraphicsScene(); - CustomView *view = new CustomView; - view->setScene(scene); + CustomView view; + view.setWindowTitle(QTest::currentTestFunction()); + view.setScene(scene); scene->addItem(backItem); rectItem->setCacheMode(QGraphicsItem::DeviceCoordinateCache); backItem->setTransform(QTransform().rotate(15), true); - view->show(); - QVERIFY(QTest::qWaitForWindowExposed(view)); - view->repaints = 0; + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + view.repaints = 0; rectItem->update(10, 10, 10, 10); - QTRY_VERIFY(view->repaints > 0); + QTRY_VERIFY(view.repaints > 0); QPixmap pix; QGraphicsItemPrivate* itemp = QGraphicsItemPrivate::get(rectItem); - QTRY_VERIFY(QPixmapCache::find(itemp->extraItemCache()->deviceData.value(view->viewport()).key, &pix)); + QTRY_VERIFY(QPixmapCache::find(itemp->extraItemCache()->deviceData.value(view.viewport()).key, &pix)); QTransform t = rectItem->sceneTransform(); // Map from scene coordinates to pixmap coordinates. // X origin in the pixmap is the most-left point // of the item's boundingRect in the scene. - qreal adjust = t.mapRect(rectItem->boundingRect().toRect()).left(); + const int adjust = t.mapRect(rectItem->boundingRect().toRect()).left(); QRect rect = t.mapRect(QRect(10, 10, 10, 10)).adjusted(-adjust, 0, -adjust + 1, 1); QPixmap subpix = pix.copy(rect); @@ -4434,8 +4473,6 @@ void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() QCOMPARE(qAlpha(im.pixel(i, j)), 125); } } - - delete view; } // Test using ItemCoordinateCache and opaque item @@ -4444,18 +4481,19 @@ void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() rectItem->setBrush(QColor(0, 0, 255)); QGraphicsScene *scene = new QGraphicsScene(); - CustomView *view = new CustomView; - view->setScene(scene); + CustomView view; + view.setWindowTitle(QTest::currentTestFunction()); + view.setScene(scene); scene->addItem(rectItem); rectItem->setCacheMode(QGraphicsItem::ItemCoordinateCache); rectItem->setTransform(QTransform().rotate(15), true); - view->show(); - QVERIFY(QTest::qWaitForWindowExposed(view)); - view->repaints = 0; + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + view.repaints = 0; rectItem->update(10, 10, 10, 10); - QTRY_VERIFY(view->repaints > 0); + QTRY_VERIFY(view.repaints > 0); QPixmap pix; QGraphicsItemPrivate* itemp = QGraphicsItemPrivate::get(rectItem); @@ -4465,7 +4503,7 @@ void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() // Map from scene coordinates to pixmap coordinates. // X origin in the pixmap is the most-left point // of the item's boundingRect in the scene. - qreal adjust = t.mapRect(rectItem->boundingRect().toRect()).left(); + const int adjust = t.mapRect(rectItem->boundingRect().toRect()).left(); QRect rect = t.mapRect(QRect(10, 10, 10, 10)).adjusted(-adjust, 0, -adjust + 1, 1); QPixmap subpix = pix.copy(rect); @@ -4474,8 +4512,6 @@ void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() for(int j = 0; j < im.height(); j++) QCOMPARE(qAlpha(im.pixel(i, j)), 255); } - - delete view; } // Test using ItemCoordinateCache and semi-transparent item @@ -4484,18 +4520,19 @@ void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() rectItem->setBrush(QColor(0, 0, 255, 125)); QGraphicsScene *scene = new QGraphicsScene(); - CustomView *view = new CustomView; - view->setScene(scene); + CustomView view; + view.setWindowTitle(QTest::currentTestFunction()); + view.setScene(scene); scene->addItem(rectItem); rectItem->setCacheMode(QGraphicsItem::ItemCoordinateCache); rectItem->setTransform(QTransform().rotate(15), true); - view->show(); - QVERIFY(QTest::qWaitForWindowExposed(view)); - view->repaints = 0; + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + view.repaints = 0; rectItem->update(10, 10, 10, 10); - QTRY_VERIFY(view->repaints > 0); + QTRY_VERIFY(view.repaints > 0); QPixmap pix; QGraphicsItemPrivate* itemp = QGraphicsItemPrivate::get(rectItem); @@ -4505,7 +4542,7 @@ void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() // Map from scene coordinates to pixmap coordinates. // X origin in the pixmap is the most-left point // of the item's boundingRect in the scene. - qreal adjust = t.mapRect(rectItem->boundingRect().toRect()).left(); + const int adjust = int(t.mapRect(rectItem->boundingRect().toRect()).left()); QRect rect = t.mapRect(QRect(10, 10, 10, 10)).adjusted(-adjust, 0, -adjust + 1, 1); QPixmap subpix = pix.copy(rect); @@ -4514,8 +4551,6 @@ void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() for(int j = 0; j < im.height(); j++) QCOMPARE(qAlpha(im.pixel(i, j)), 125); } - - delete view; } } @@ -4546,7 +4581,7 @@ void tst_QGraphicsScene::zeroScale() QGraphicsView view(&scene); ChangedListener cl; - connect(&scene, SIGNAL(changed(QList)), &cl, SLOT(changed(QList))); + connect(&scene, &QGraphicsScene::changed, &cl, &ChangedListener::changed); QGraphicsRectItem *rect1 = new QGraphicsRectItem(0, 0, 0.0000001, 0.00000001); scene.addItem(rect1); @@ -4569,13 +4604,13 @@ void tst_QGraphicsScene::focusItemChangedSignal() qRegisterMetaType("Qt::FocusReason"); QGraphicsScene scene; - QSignalSpy spy(&scene, SIGNAL(focusItemChanged(QGraphicsItem *, QGraphicsItem *, Qt::FocusReason))); + QSignalSpy spy(&scene, &QGraphicsScene::focusItemChanged); QVERIFY(spy.isValid()); QCOMPARE(spy.count(), 0); scene.setFocus(); QCOMPARE(spy.count(), 0); QEvent activateEvent(QEvent::WindowActivate); - qApp->sendEvent(&scene, &activateEvent); + QCoreApplication::sendEvent(&scene, &activateEvent); QCOMPARE(spy.count(), 0); QGraphicsRectItem *topLevelItem1 = new QGraphicsRectItem; @@ -4592,7 +4627,7 @@ void tst_QGraphicsScene::focusItemChangedSignal() QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); QCOMPARE(arguments.size(), 3); - QCOMPARE(qvariant_cast(arguments.at(0)), (QGraphicsItem *)topLevelItem2); + QCOMPARE(qvariant_cast(arguments.at(0)), topLevelItem2); QCOMPARE(qvariant_cast(arguments.at(1)), nullptr); QCOMPARE(qvariant_cast(arguments.at(2)), Qt::OtherFocusReason); QVERIFY(topLevelItem2->hasFocus()); @@ -4602,14 +4637,14 @@ void tst_QGraphicsScene::focusItemChangedSignal() arguments = spy.takeFirst(); QCOMPARE(arguments.size(), 3); QCOMPARE(qvariant_cast(arguments.at(0)), nullptr); - QCOMPARE(qvariant_cast(arguments.at(1)), (QGraphicsItem *)topLevelItem2); + QCOMPARE(qvariant_cast(arguments.at(1)), topLevelItem2); QCOMPARE(qvariant_cast(arguments.at(2)), Qt::OtherFocusReason); scene.setFocus(Qt::MenuBarFocusReason); QCOMPARE(spy.count(), 1); arguments = spy.takeFirst(); QCOMPARE(arguments.size(), 3); - QCOMPARE(qvariant_cast(arguments.at(0)), (QGraphicsItem *)topLevelItem2); + QCOMPARE(qvariant_cast(arguments.at(0)), topLevelItem2); QCOMPARE(qvariant_cast(arguments.at(1)), nullptr); QCOMPARE(qvariant_cast(arguments.at(2)), Qt::MenuBarFocusReason); @@ -4617,15 +4652,15 @@ void tst_QGraphicsScene::focusItemChangedSignal() topLevelItem1->setFocus(Qt::TabFocusReason); arguments = spy.takeFirst(); QCOMPARE(arguments.size(), 3); - QCOMPARE(qvariant_cast(arguments.at(0)), (QGraphicsItem *)topLevelItem1); - QCOMPARE(qvariant_cast(arguments.at(1)), (QGraphicsItem *)topLevelItem2); + QCOMPARE(qvariant_cast(arguments.at(0)), topLevelItem1); + QCOMPARE(qvariant_cast(arguments.at(1)), topLevelItem2); QCOMPARE(qvariant_cast(arguments.at(2)), Qt::TabFocusReason); topLevelItem2->setFocus(Qt::TabFocusReason); arguments = spy.takeFirst(); QCOMPARE(arguments.size(), 3); - QCOMPARE(qvariant_cast(arguments.at(0)), (QGraphicsItem *)topLevelItem2); - QCOMPARE(qvariant_cast(arguments.at(1)), (QGraphicsItem *)topLevelItem1); + QCOMPARE(qvariant_cast(arguments.at(0)), topLevelItem2); + QCOMPARE(qvariant_cast(arguments.at(1)), topLevelItem1); QCOMPARE(qvariant_cast(arguments.at(2)), Qt::TabFocusReason); } @@ -4633,10 +4668,10 @@ void tst_QGraphicsScene::focusItemChangedSignal() // when the scene activation changes) breaks quite a few tests so leave this fix // for some future release. See QTBUG-28346. QEvent deactivateEvent(QEvent::WindowDeactivate); - qApp->sendEvent(&scene, &deactivateEvent); + QCoreApplication::sendEvent(&scene, &deactivateEvent); QEXPECT_FAIL("", "QTBUG-28346", Continue); QCOMPARE(spy.count(), 1); - qApp->sendEvent(&scene, &activateEvent); + QCoreApplication::sendEvent(&scene, &activateEvent); QEXPECT_FAIL("", "QTBUG-28346", Continue); QCOMPARE(spy.count(), 1); @@ -4647,8 +4682,8 @@ void tst_QGraphicsScene::focusItemChangedSignal() QCOMPARE(spy.count(), 1); arguments = spy.takeFirst(); QCOMPARE(arguments.size(), 3); - QCOMPARE(qvariant_cast(arguments.at(0)), (QGraphicsItem *)panel1); - QCOMPARE(qvariant_cast(arguments.at(1)), (QGraphicsItem *)topLevelItem2); + QCOMPARE(qvariant_cast(arguments.at(0)), panel1); + QCOMPARE(qvariant_cast(arguments.at(1)), topLevelItem2); QCOMPARE(qvariant_cast(arguments.at(2)), Qt::ActiveWindowFocusReason); QGraphicsRectItem *panel2 = new QGraphicsRectItem; @@ -4661,16 +4696,16 @@ void tst_QGraphicsScene::focusItemChangedSignal() QCOMPARE(spy.count(), 1); arguments = spy.takeFirst(); QCOMPARE(arguments.size(), 3); - QCOMPARE(qvariant_cast(arguments.at(0)), (QGraphicsItem *)panel2); - QCOMPARE(qvariant_cast(arguments.at(1)), (QGraphicsItem *)panel1); + QCOMPARE(qvariant_cast(arguments.at(0)), panel2); + QCOMPARE(qvariant_cast(arguments.at(1)), panel1); QCOMPARE(qvariant_cast(arguments.at(2)), Qt::ActiveWindowFocusReason); scene.setActivePanel(panel1); QCOMPARE(spy.count(), 1); arguments = spy.takeFirst(); QCOMPARE(arguments.size(), 3); - QCOMPARE(qvariant_cast(arguments.at(0)), (QGraphicsItem *)panel1); - QCOMPARE(qvariant_cast(arguments.at(1)), (QGraphicsItem *)panel2); + QCOMPARE(qvariant_cast(arguments.at(0)), panel1); + QCOMPARE(qvariant_cast(arguments.at(1)), panel2); QCOMPARE(qvariant_cast(arguments.at(2)), Qt::ActiveWindowFocusReason); } @@ -4679,14 +4714,15 @@ void tst_QGraphicsScene::focusItemChangedSignal() class ItemCountsPaintCalls : public QGraphicsRectItem { public: - ItemCountsPaintCalls(const QRectF & rect, QGraphicsItem *parent = 0) - : QGraphicsRectItem(rect, parent), repaints(0) {} - void paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0 ) + using QGraphicsRectItem::QGraphicsRectItem; + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, + QWidget *widget = nullptr) override { QGraphicsRectItem::paint(painter, option, widget); ++repaints; } - int repaints; + int repaints = 0; }; void tst_QGraphicsScene::minimumRenderSize() @@ -4700,10 +4736,11 @@ void tst_QGraphicsScene::minimumRenderSize() scene.addItem(bigParent); CustomView view; + view.setWindowTitle(QTest::currentTestFunction()); view.setScene(&scene); view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); - qApp->processEvents(); + QCoreApplication::processEvents(); // Initially, everything should be repainted the same number of times int viewRepaints = 0; @@ -4716,7 +4753,7 @@ void tst_QGraphicsScene::minimumRenderSize() // Setting a minimum render size should cause a repaint scene.setMinimumRenderSize(0.5); - qApp->processEvents(); + QCoreApplication::processEvents(); QTRY_VERIFY(view.repaints > viewRepaints); viewRepaints = view.repaints; @@ -4727,7 +4764,7 @@ void tst_QGraphicsScene::minimumRenderSize() // Scaling should cause a repaint of big items only. view.scale(0.1, 0.1); - qApp->processEvents(); + QCoreApplication::processEvents(); QTRY_VERIFY(view.repaints > viewRepaints); viewRepaints = view.repaints; @@ -4738,7 +4775,7 @@ void tst_QGraphicsScene::minimumRenderSize() // Scaling further should cause even fewer items to be repainted view.scale(0.1, 0.1); // Stacks with previous scale - qApp->processEvents(); + QCoreApplication::processEvents(); QTRY_VERIFY(view.repaints > viewRepaints); viewRepaints = view.repaints; @@ -4752,6 +4789,7 @@ void tst_QGraphicsScene::focusOnTouch() { QGraphicsScene scene; QGraphicsView view(&scene); + view.setWindowTitle(QTest::currentTestFunction()); scene.setSceneRect(0, 0, 100, 100); QGraphicsRectItem *rect = scene.addRect(0, 0, 100, 100); rect->setFlag(QGraphicsItem::ItemIsFocusable, true); @@ -4839,6 +4877,7 @@ void tst_QGraphicsScene::taskQTBUG_42915_focusNextPrevChild() { QGraphicsScene scene; QGraphicsView view(&scene); + view.setWindowTitle(QTest::currentTestFunction()); scene.setSceneRect(1, 1, 198, 198); view.setFocus(); -- cgit v1.2.3 From c2aaa9e18ecc62cb399010f063c6938771a92563 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 16 Aug 2019 10:06:56 +0200 Subject: tst_QGraphicsScene: Pass on High DPI screens The test requires High DPI scaling to be disabled since it captures widgets. Turn it off initially and introduce a member variable containing a suitable size depending on the screen to make the test pass on High DPI screens without violating minimum window widths on Windows. Change-Id: Ida9f306cff6abd48ee5de7001c7670a0da60c6c2 Reviewed-by: Oliver Wolff --- .../qgraphicsscene/tst_qgraphicsscene.cpp | 75 ++++++++++++++++------ 1 file changed, 55 insertions(+), 20 deletions(-) diff --git a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp index cc6ed2f80e..950f3ef670 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp @@ -182,6 +182,10 @@ protected: class tst_QGraphicsScene : public QObject { Q_OBJECT +public: + tst_QGraphicsScene(); + static void initMain() { QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); } + public slots: void cleanup(); @@ -284,8 +288,19 @@ private slots: void taskQTBUG_15977_renderWithDeviceCoordinateCache(); void taskQTBUG_16401_focusItem(); void taskQTBUG_42915_focusNextPrevChild(); + +private: + QRect m_availableGeometry = QGuiApplication::primaryScreen()->availableGeometry(); + QSize m_testSize; }; +tst_QGraphicsScene::tst_QGraphicsScene() +{ + const int testSize = qMax(200, m_availableGeometry.width() / 10); + m_testSize.setWidth(testSize); + m_testSize.setHeight(testSize); +} + void tst_QGraphicsScene::cleanup() { // ensure not even skipped tests with custom input context leave it dangling @@ -1085,6 +1100,7 @@ void tst_QGraphicsScene::addItem() CustomView view; view.setWindowTitle(QTest::currentTestFunction()); view.setScene(&scene); + view.resize(m_testSize); view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); QCoreApplication::processEvents(); @@ -2597,6 +2613,7 @@ void tst_QGraphicsScene::render() QGraphicsView view; view.setWindowTitle(QTest::currentTestFunction()); + view.resize(m_testSize); QGraphicsScene scene(&view); scene.addEllipse(QRectF(-10, -10, 20, 20), QPen(Qt::black, 0), QBrush(Qt::white)); scene.addEllipse(QRectF(-2, -7, 4, 4), QPen(Qt::black, 0), QBrush(Qt::yellow))->setZValue(1); @@ -2678,34 +2695,32 @@ void tst_QGraphicsScene::renderItemsWithNegativeWidthOrHeight() #if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) || defined(Q_OS_WINRT) QSKIP("Test only works on platforms with resizable windows"); #endif - - QGraphicsScene scene(0, 0, 150, 150); + QGraphicsScene scene(0, 0, m_testSize.width(), m_testSize.height()); // Add item with negative width. - QGraphicsRectItem *item1 = new QGraphicsRectItem(0, 0, -150, 50); + QGraphicsRectItem *item1 = new QGraphicsRectItem(0, 0, -m_testSize.width(), 50); item1->setBrush(Qt::red); - item1->setPos(150, 50); + item1->setPos(m_testSize.width(), 50); scene.addItem(item1); // Add item with negative height. - QGraphicsRectItem *item2 = new QGraphicsRectItem(0, 0, 50, -150); + QGraphicsRectItem *item2 = new QGraphicsRectItem(0, 0, 50, -m_testSize.height()); item2->setBrush(Qt::blue); - item2->setPos(50, 150); + item2->setPos(50, m_testSize.height()); scene.addItem(item2); QGraphicsView view(&scene); view.setWindowTitle(QTest::currentTestFunction()); view.setFrameStyle(QFrame::NoFrame); - view.resize(150, 150); view.show(); - QCOMPARE(view.viewport()->size(), QSize(150, 150)); + QTRY_COMPARE(view.viewport()->size(), m_testSize); QImage expected(view.viewport()->size(), QImage::Format_RGB32); view.viewport()->render(&expected); // Make sure the scene background is the same as the viewport background. scene.setBackgroundBrush(view.viewport()->palette().brush(view.viewport()->backgroundRole())); - QImage actual(150, 150, QImage::Format_RGB32); + QImage actual(m_testSize, QImage::Format_RGB32); QPainter painter(&actual); scene.render(&painter); painter.end(); @@ -2730,6 +2745,7 @@ void tst_QGraphicsScene::contextMenuEvent() QGraphicsView view(&scene); view.setWindowTitle(QTest::currentTestFunction()); + view.resize(m_testSize); view.show(); view.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&view)); @@ -2746,7 +2762,7 @@ void tst_QGraphicsScene::contextMenuEvent() class ContextMenuItem : public QGraphicsRectItem { public: - ContextMenuItem() : QGraphicsRectItem(0, 0, 100, 100) + ContextMenuItem(const QSize &s) : QGraphicsRectItem(0, 0, s.width(), s.height()) { setBrush(Qt::red); } protected: @@ -2760,27 +2776,30 @@ void tst_QGraphicsScene::contextMenuEvent_ItemIgnoresTransformations() QSKIP("Test fails on some Android devices (QTBUG-44430)"); #endif - QGraphicsScene scene(0, 0, 200, 200); - ContextMenuItem *item = new ContextMenuItem; + QGraphicsScene scene(0, 0, m_testSize.width(), m_testSize.height()); + const QSize itemSize = m_testSize / 2; + ContextMenuItem *item = new ContextMenuItem(itemSize); item->setFlag(QGraphicsItem::ItemIgnoresTransformations); scene.addItem(item); QWidget topLevel; topLevel.setWindowTitle(QTest::currentTestFunction()); + topLevel.resize(m_testSize); QGraphicsView view(&scene, &topLevel); - view.resize(200, 200); topLevel.show(); QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + + { - QPoint pos(50, 50); + QPoint pos(itemSize.width() / 2, itemSize.height() / 2); QContextMenuEvent event(QContextMenuEvent::Keyboard, pos, view.viewport()->mapToGlobal(pos)); event.ignore(); QApplication::sendEvent(view.viewport(), &event); QVERIFY(event.isAccepted()); } { - QPoint pos(150, 150); + QPoint pos(itemSize.width() * 3 / 2, itemSize.height() * 3 / 2); QContextMenuEvent event(QContextMenuEvent::Keyboard, pos, view.viewport()->mapToGlobal(pos)); event.ignore(); QApplication::sendEvent(view.viewport(), &event); @@ -2788,14 +2807,14 @@ void tst_QGraphicsScene::contextMenuEvent_ItemIgnoresTransformations() } view.scale(1.5, 1.5); { - QPoint pos(25, 25); + QPoint pos(itemSize.width() / 4, itemSize.height() / 4); QContextMenuEvent event(QContextMenuEvent::Keyboard, pos, view.viewport()->mapToGlobal(pos)); event.ignore(); QApplication::sendEvent(view.viewport(), &event); QVERIFY(event.isAccepted()); } { - QPoint pos(55, 55); + QPoint pos(itemSize.width() / 2 + 5, itemSize.height() / 2 + 5); QContextMenuEvent event(QContextMenuEvent::Keyboard, pos, view.viewport()->mapToGlobal(pos)); event.ignore(); QApplication::sendEvent(view.viewport(), &event); @@ -2844,6 +2863,7 @@ void tst_QGraphicsScene::update2() scene.setSceneRect(-200, -200, 200, 200); CustomView view; view.setWindowTitle(QTest::currentTestFunction()); + view.resize(m_testSize); view.setScene(&scene); view.show(); QApplication::setActiveWindow(&view); @@ -3514,6 +3534,7 @@ void tst_QGraphicsScene::task160653_selectionChanged() QSignalSpy spy(&scene, &QGraphicsScene::selectionChanged); QGraphicsView view(&scene); view.setWindowTitle(QTest::currentTestFunction()); + view.resize(m_testSize); view.show(); QVERIFY(QTest::qWaitForWindowActive(&view)); QTest::mouseClick( @@ -3803,6 +3824,7 @@ void tst_QGraphicsScene::inputMethod() QGraphicsScene scene; QGraphicsView view(&scene); + view.resize(m_testSize); view.show(); view.setWindowTitle(QTest::currentTestFunction()); QApplication::setActiveWindow(&view); @@ -4044,6 +4066,7 @@ void tst_QGraphicsScene::isActive() { QWidget toplevel1; toplevel1.setWindowTitle(QTest::currentTestFunction()); + toplevel1.resize(m_testSize); QHBoxLayout *layout = new QHBoxLayout; toplevel1.setLayout(layout); QGraphicsView *view1 = new QGraphicsView(&scene1); @@ -4109,9 +4132,9 @@ void tst_QGraphicsScene::isActive() { - const QRect availableGeometry = QGuiApplication::primaryScreen()->availableGeometry(); QWidget toplevel2; toplevel2.setWindowTitle(QTest::currentTestFunction()); + toplevel2.resize(m_testSize); QHBoxLayout *layout = new QHBoxLayout; toplevel2.setLayout(layout); QGraphicsView *view1 = new QGraphicsView(&scene1); @@ -4124,7 +4147,7 @@ void tst_QGraphicsScene::isActive() QVERIFY(!scene1.hasFocus()); QVERIFY(!scene2.hasFocus()); - toplevel2.move(availableGeometry.topLeft() + QPoint(50, 50)); + toplevel2.move(m_availableGeometry.topLeft() + QPoint(50, 50)); toplevel2.show(); QApplication::setActiveWindow(&toplevel2); QVERIFY(QTest::qWaitForWindowActive(&toplevel2)); @@ -4173,7 +4196,8 @@ void tst_QGraphicsScene::isActive() QVERIFY(!scene2.hasFocus()); QGraphicsView topLevelView; - topLevelView.move(availableGeometry.topLeft() + QPoint(500, 50)); + topLevelView.move(toplevel2.geometry().topRight() + QPoint(100, 50)); + topLevelView.resize(m_testSize); topLevelView.show(); QApplication::setActiveWindow(&topLevelView); topLevelView.setFocus(); @@ -4219,6 +4243,7 @@ void tst_QGraphicsScene::isActive() { QWidget toplevel3; + toplevel3.resize(m_testSize); QHBoxLayout *layout = new QHBoxLayout; toplevel3.setLayout(layout); QGraphicsView *view1 = new QGraphicsView(&scene1); @@ -4297,6 +4322,7 @@ void tst_QGraphicsScene::siblingIndexAlwaysValid() QGraphicsView view2(&scene2); view2.setWindowTitle(QTest::currentTestFunction()); + view2.resize(m_testSize); // first add the blue rect QGraphicsRectItem* const item1 = new QGraphicsRectItem(QRect( 10, 10, 10, 10 )); @@ -4341,6 +4367,7 @@ void tst_QGraphicsScene::removeFullyTransparentItem() CustomView view; view.setWindowTitle(QTest::currentTestFunction()); + view.resize(m_testSize); view.setScene(&scene); view.show(); QApplication::setActiveWindow(&view); @@ -4398,6 +4425,7 @@ void tst_QGraphicsScene::taskQT657_paintIntoCacheWithTransparentParts() QGraphicsScene *scene = new QGraphicsScene(); CustomView view; + view.resize(m_testSize); view.setWindowTitle(QTest::currentTestFunction()); view.setScene(scene); @@ -4442,6 +4470,7 @@ void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() QGraphicsScene *scene = new QGraphicsScene(); CustomView view; + view.resize(m_testSize); view.setWindowTitle(QTest::currentTestFunction()); view.setScene(scene); @@ -4483,6 +4512,7 @@ void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() QGraphicsScene *scene = new QGraphicsScene(); CustomView view; view.setWindowTitle(QTest::currentTestFunction()); + view.resize(m_testSize); view.setScene(scene); scene->addItem(rectItem); @@ -4522,6 +4552,7 @@ void tst_QGraphicsScene::taskQTBUG_7863_paintIntoCacheWithTransparentParts() QGraphicsScene *scene = new QGraphicsScene(); CustomView view; view.setWindowTitle(QTest::currentTestFunction()); + view.resize(m_testSize); view.setScene(scene); scene->addItem(rectItem); @@ -4737,6 +4768,7 @@ void tst_QGraphicsScene::minimumRenderSize() CustomView view; view.setWindowTitle(QTest::currentTestFunction()); + view.resize(m_testSize); view.setScene(&scene); view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); @@ -4790,6 +4822,7 @@ void tst_QGraphicsScene::focusOnTouch() QGraphicsScene scene; QGraphicsView view(&scene); view.setWindowTitle(QTest::currentTestFunction()); + view.resize(m_testSize); scene.setSceneRect(0, 0, 100, 100); QGraphicsRectItem *rect = scene.addRect(0, 0, 100, 100); rect->setFlag(QGraphicsItem::ItemIsFocusable, true); @@ -4847,6 +4880,7 @@ void tst_QGraphicsScene::taskQTBUG_16401_focusItem() { QGraphicsScene scene; QGraphicsView view(&scene); + view.resize(m_testSize); QGraphicsRectItem *rect = scene.addRect(0, 0, 100, 100); rect->setFlag(QGraphicsItem::ItemIsFocusable); @@ -4878,6 +4912,7 @@ void tst_QGraphicsScene::taskQTBUG_42915_focusNextPrevChild() QGraphicsScene scene; QGraphicsView view(&scene); view.setWindowTitle(QTest::currentTestFunction()); + view.resize(m_testSize); scene.setSceneRect(1, 1, 198, 198); view.setFocus(); -- cgit v1.2.3 From 77de5a329c98c3787725cb3c0a50d8f369b9479c Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Aug 2014 22:37:13 +0200 Subject: Long live QColorConstants! QColorConstant is a C++11 version of Qt::GlobalColor, except that instead of Qt::red being an enum, QColorConstants::red is an actual QColor instance, a bit like in the Qt 3 days. In addition, the SVG names that QColor understands are also available, with the same values. Technically, when building a QColor from a color name, QColor ignores casing and whitespaces; we stick to the SVG/CSS official color names (which are lowercase), and prefix them with Svg to clarify where they come from. For instance, note how SVG's gray is not Qt::gray. [ChangeLog][QtGui][[QColor] Added QColorConstants, a namespace containing constexpr QColor instances. Change-Id: Ic9fab26a9a537fcc43cc230da28f4c6314a32438 Reviewed-by: Marc Mutz --- src/gui/doc/qtgui.qdocconf | 3 + src/gui/doc/src/includes/qt-colors.qdocinc | 86 ++++ src/gui/doc/src/includes/svg-colors.qdocinc | 594 ++++++++++++++++++++++++++ src/gui/painting/qcolor.cpp | 81 +++- src/gui/painting/qcolor.h | 187 ++++++++ tests/auto/gui/painting/qcolor/tst_qcolor.cpp | 189 ++++++++ 6 files changed, 1124 insertions(+), 16 deletions(-) create mode 100644 src/gui/doc/src/includes/qt-colors.qdocinc create mode 100644 src/gui/doc/src/includes/svg-colors.qdocinc diff --git a/src/gui/doc/qtgui.qdocconf b/src/gui/doc/qtgui.qdocconf index 049b9ef179..76dd6d7ea1 100644 --- a/src/gui/doc/qtgui.qdocconf +++ b/src/gui/doc/qtgui.qdocconf @@ -67,3 +67,6 @@ navigation.cppclassespage = "Qt GUI C++ Classes" # Ignore warnings about undocumented enum values for the QGradient presets spurious += "Undocumented enum item '.*' in QGradient::Preset" + +# \svgcolor {#ffdead} +macro.svgcolor.HTML = "
" diff --git a/src/gui/doc/src/includes/qt-colors.qdocinc b/src/gui/doc/src/includes/qt-colors.qdocinc new file mode 100644 index 0000000000..4c082323b6 --- /dev/null +++ b/src/gui/doc/src/includes/qt-colors.qdocinc @@ -0,0 +1,86 @@ +\table +\header + \li Name + \li Hex + \li Color +\row + \li Color0 + \li #000000 + \li \svgcolor {#000000} +\row + \li Color1 + \li #ffffff + \li \svgcolor {#ffffff} +\row + \li Black + \li #000000 + \li \svgcolor {#000000} +\row + \li White + \li #ffffff + \li \svgcolor {#ffffff} +\row + \li DarkGray + \li #808080 + \li \svgcolor {#808080} +\row + \li Gray + \li #a0a0a4 + \li \svgcolor {#a0a0a4} +\row + \li LightGray + \li #c0c0c0 + \li \svgcolor {#c0c0c0} +\row + \li Red + \li #ff0000 + \li \svgcolor {#ff0000} +\row + \li Green + \li #00ff00 + \li \svgcolor {#00ff00} +\row + \li Blue + \li #0000ff + \li \svgcolor {#0000ff} +\row + \li Cyan + \li #00ffff + \li \svgcolor {#00ffff} +\row + \li Magenta + \li #ff00ff + \li \svgcolor {#ff00ff} +\row + \li Yellow + \li #ffff00 + \li \svgcolor {#ffff00} +\row + \li DarkRed + \li #800000 + \li \svgcolor {#800000} +\row + \li DarkGreen + \li #008000 + \li \svgcolor {#008000} +\row + \li DarkBlue + \li #000080 + \li \svgcolor {#000080} +\row + \li DarkCyan + \li #008080 + \li \svgcolor {#008080} +\row + \li DarkMagenta + \li #800080 + \li \svgcolor {#800080} +\row + \li DarkYellow + \li #808000 + \li \svgcolor {#808000} +\row + \li Transparent + \li #00000000 + \li (transparent) +\endtable diff --git a/src/gui/doc/src/includes/svg-colors.qdocinc b/src/gui/doc/src/includes/svg-colors.qdocinc new file mode 100644 index 0000000000..4e5fb56d5e --- /dev/null +++ b/src/gui/doc/src/includes/svg-colors.qdocinc @@ -0,0 +1,594 @@ +\table +\header + \li Name + \li Hex + \li Color +\row + \li aliceblue + \li #f0f8ff + \li \svgcolor {#f0f8ff} +\row + \li antiquewhite + \li #faebd7 + \li \svgcolor {#faebd7} +\row + \li aqua + \li #00ffff + \li \svgcolor {#00ffff} +\row + \li aquamarine + \li #7fffd4 + \li \svgcolor {#7fffd4} +\row + \li azure + \li #f0ffff + \li \svgcolor {#f0ffff} +\row + \li beige + \li #f5f5dc + \li \svgcolor {#f5f5dc} +\row + \li bisque + \li #ffe4c4 + \li \svgcolor {#ffe4c4} +\row + \li black + \li #000000 + \li \svgcolor {#000000} +\row + \li blanchedalmond + \li #ffebcd + \li \svgcolor {#ffebcd} +\row + \li blue + \li #0000ff + \li \svgcolor {#0000ff} +\row + \li blueviolet + \li #8a2be2 + \li \svgcolor {#8a2be2} +\row + \li brown + \li #a52a2a + \li \svgcolor {#a52a2a} +\row + \li burlywood + \li #deb887 + \li \svgcolor {#deb887} +\row + \li cadetblue + \li #5f9ea0 + \li \svgcolor {#5f9ea0} +\row + \li chartreuse + \li #7fff00 + \li \svgcolor {#7fff00} +\row + \li chocolate + \li #d2691e + \li \svgcolor {#d2691e} +\row + \li coral + \li #ff7f50 + \li \svgcolor {#ff7f50} +\row + \li cornflowerblue + \li #6495ed + \li \svgcolor {#6495ed} +\row + \li cornsilk + \li #fff8dc + \li \svgcolor {#fff8dc} +\row + \li crimson + \li #dc143c + \li \svgcolor {#dc143c} +\row + \li cyan + \li #00ffff + \li \svgcolor {#00ffff} +\row + \li darkblue + \li #00008b + \li \svgcolor {#00008b} +\row + \li darkcyan + \li #008b8b + \li \svgcolor {#008b8b} +\row + \li darkgoldenrod + \li #b8860b + \li \svgcolor {#b8860b} +\row + \li darkgray + \li #a9a9a9 + \li \svgcolor {#a9a9a9} +\row + \li darkgreen + \li #006400 + \li \svgcolor {#006400} +\row + \li darkgrey + \li #a9a9a9 + \li \svgcolor {#a9a9a9} +\row + \li darkkhaki + \li #bdb76b + \li \svgcolor {#bdb76b} +\row + \li darkmagenta + \li #8b008b + \li \svgcolor {#8b008b} +\row + \li darkolivegreen + \li #556b2f + \li \svgcolor {#556b2f} +\row + \li darkorange + \li #ff8c00 + \li \svgcolor {#ff8c00} +\row + \li darkorchid + \li #9932cc + \li \svgcolor {#9932cc} +\row + \li darkred + \li #8b0000 + \li \svgcolor {#8b0000} +\row + \li darksalmon + \li #e9967a + \li \svgcolor {#e9967a} +\row + \li darkseagreen + \li #8fbc8f + \li \svgcolor {#8fbc8f} +\row + \li darkslateblue + \li #483d8b + \li \svgcolor {#483d8b} +\row + \li darkslategray + \li #2f4f4f + \li \svgcolor {#2f4f4f} +\row + \li darkslategrey + \li #2f4f4f + \li \svgcolor {#2f4f4f} +\row + \li darkturquoise + \li #00ced1 + \li \svgcolor {#00ced1} +\row + \li darkviolet + \li #9400d3 + \li \svgcolor {#9400d3} +\row + \li deeppink + \li #ff1493 + \li \svgcolor {#ff1493} +\row + \li deepskyblue + \li #00bfff + \li \svgcolor {#00bfff} +\row + \li dimgray + \li #696969 + \li \svgcolor {#696969} +\row + \li dimgrey + \li #696969 + \li \svgcolor {#696969} +\row + \li dodgerblue + \li #1e90ff + \li \svgcolor {#1e90ff} +\row + \li firebrick + \li #b22222 + \li \svgcolor {#b22222} +\row + \li floralwhite + \li #fffaf0 + \li \svgcolor {#fffaf0} +\row + \li forestgreen + \li #228b22 + \li \svgcolor {#228b22} +\row + \li fuchsia + \li #ff00ff + \li \svgcolor {#ff00ff} +\row + \li gainsboro + \li #dcdcdc + \li \svgcolor {#dcdcdc} +\row + \li ghostwhite + \li #f8f8ff + \li \svgcolor {#f8f8ff} +\row + \li gold + \li #ffd700 + \li \svgcolor {#ffd700} +\row + \li goldenrod + \li #daa520 + \li \svgcolor {#daa520} +\row + \li gray + \li #808080 + \li \svgcolor {#808080} +\row + \li grey + \li #808080 + \li \svgcolor {#808080} +\row + \li green + \li #008000 + \li \svgcolor {#008000} +\row + \li greenyellow + \li #adff2f + \li \svgcolor {#adff2f} +\row + \li honeydew + \li #f0fff0 + \li \svgcolor {#f0fff0} +\row + \li hotpink + \li #ff69b4 + \li \svgcolor {#ff69b4} +\row + \li indianred + \li #cd5c5c + \li \svgcolor {#cd5c5c} +\row + \li indigo + \li #4b0082 + \li \svgcolor {#4b0082} +\row + \li ivory + \li #fffff0 + \li \svgcolor {#fffff0} +\row + \li khaki + \li #f0e68c + \li \svgcolor {#f0e68c} +\row + \li lavender + \li #e6e6fa + \li \svgcolor {#e6e6fa} +\row + \li lavenderblush + \li #fff0f5 + \li \svgcolor {#fff0f5} +\row + \li lawngreen + \li #7cfc00 + \li \svgcolor {#7cfc00} +\row + \li lemonchiffon + \li #fffacd + \li \svgcolor {#fffacd} +\row + \li lightblue + \li #add8e6 + \li \svgcolor {#add8e6} +\row + \li lightcoral + \li #f08080 + \li \svgcolor {#f08080} +\row + \li lightcyan + \li #e0ffff + \li \svgcolor {#e0ffff} +\row + \li lightgoldenrodyellow + \li #fafad2 + \li \svgcolor {#fafad2} +\row + \li lightgray + \li #d3d3d3 + \li \svgcolor {#d3d3d3} +\row + \li lightgreen + \li #90ee90 + \li \svgcolor {#90ee90} +\row + \li lightgrey + \li #d3d3d3 + \li \svgcolor {#d3d3d3} +\row + \li lightpink + \li #ffb6c1 + \li \svgcolor {#ffb6c1} +\row + \li lightsalmon + \li #ffa07a + \li \svgcolor {#ffa07a} +\row + \li lightseagreen + \li #20b2aa + \li \svgcolor {#20b2aa} +\row + \li lightskyblue + \li #87cefa + \li \svgcolor {#87cefa} +\row + \li lightslategray + \li #778899 + \li \svgcolor {#778899} +\row + \li lightslategrey + \li #778899 + \li \svgcolor {#778899} +\row + \li lightsteelblue + \li #b0c4de + \li \svgcolor {#b0c4de} +\row + \li lightyellow + \li #ffffe0 + \li \svgcolor {#ffffe0} +\row + \li lime + \li #00ff00 + \li \svgcolor {#00ff00} +\row + \li limegreen + \li #32cd32 + \li \svgcolor {#32cd32} +\row + \li linen + \li #faf0e6 + \li \svgcolor {#faf0e6} +\row + \li magenta + \li #ff00ff + \li \svgcolor {#ff00ff} +\row + \li maroon + \li #800000 + \li \svgcolor {#800000} +\row + \li mediumaquamarine + \li #66cdaa + \li \svgcolor {#66cdaa} +\row + \li mediumblue + \li #0000cd + \li \svgcolor {#0000cd} +\row + \li mediumorchid + \li #ba55d3 + \li \svgcolor {#ba55d3} +\row + \li mediumpurple + \li #9370db + \li \svgcolor {#9370db} +\row + \li mediumseagreen + \li #3cb371 + \li \svgcolor {#3cb371} +\row + \li mediumslateblue + \li #7b68ee + \li \svgcolor {#7b68ee} +\row + \li mediumspringgreen + \li #00fa9a + \li \svgcolor {#00fa9a} +\row + \li mediumturquoise + \li #48d1cc + \li \svgcolor {#48d1cc} +\row + \li mediumvioletred + \li #c71585 + \li \svgcolor {#c71585} +\row + \li midnightblue + \li #191970 + \li \svgcolor {#191970} +\row + \li mintcream + \li #f5fffa + \li \svgcolor {#f5fffa} +\row + \li mistyrose + \li #ffe4e1 + \li \svgcolor {#ffe4e1} +\row + \li moccasin + \li #ffe4b5 + \li \svgcolor {#ffe4b5} +\row + \li navajowhite + \li #ffdead + \li \svgcolor {#ffdead} +\row + \li navy + \li #000080 + \li \svgcolor {#000080} +\row + \li oldlace + \li #fdf5e6 + \li \svgcolor {#fdf5e6} +\row + \li olive + \li #808000 + \li \svgcolor {#808000} +\row + \li olivedrab + \li #6b8e23 + \li \svgcolor {#6b8e23} +\row + \li orange + \li #ffa500 + \li \svgcolor {#ffa500} +\row + \li orangered + \li #ff4500 + \li \svgcolor {#ff4500} +\row + \li orchid + \li #da70d6 + \li \svgcolor {#da70d6} +\row + \li palegoldenrod + \li #eee8aa + \li \svgcolor {#eee8aa} +\row + \li palegreen + \li #98fb98 + \li \svgcolor {#98fb98} +\row + \li paleturquoise + \li #afeeee + \li \svgcolor {#afeeee} +\row + \li palevioletred + \li #db7093 + \li \svgcolor {#db7093} +\row + \li papayawhip + \li #ffefd5 + \li \svgcolor {#ffefd5} +\row + \li peachpuff + \li #ffdab9 + \li \svgcolor {#ffdab9} +\row + \li peru + \li #cd853f + \li \svgcolor {#cd853f} +\row + \li pink + \li #ffc0cb + \li \svgcolor {#ffc0cb} +\row + \li plum + \li #dda0dd + \li \svgcolor {#dda0dd} +\row + \li powderblue + \li #b0e0e6 + \li \svgcolor {#b0e0e6} +\row + \li purple + \li #800080 + \li \svgcolor {#800080} +\row + \li red + \li #ff0000 + \li \svgcolor {#ff0000} +\row + \li rosybrown + \li #bc8f8f + \li \svgcolor {#bc8f8f} +\row + \li royalblue + \li #4169e1 + \li \svgcolor {#4169e1} +\row + \li saddlebrown + \li #8b4513 + \li \svgcolor {#8b4513} +\row + \li salmon + \li #fa8072 + \li \svgcolor {#fa8072} +\row + \li sandybrown + \li #f4a460 + \li \svgcolor {#f4a460} +\row + \li seagreen + \li #2e8b57 + \li \svgcolor {#2e8b57} +\row + \li seashell + \li #fff5ee + \li \svgcolor {#fff5ee} +\row + \li sienna + \li #a0522d + \li \svgcolor {#a0522d} +\row + \li silver + \li #c0c0c0 + \li \svgcolor {#c0c0c0} +\row + \li skyblue + \li #87ceeb + \li \svgcolor {#87ceeb} +\row + \li slateblue + \li #6a5acd + \li \svgcolor {#6a5acd} +\row + \li slategray + \li #708090 + \li \svgcolor {#708090} +\row + \li slategrey + \li #708090 + \li \svgcolor {#708090} +\row + \li snow + \li #fffafa + \li \svgcolor {#fffafa} +\row + \li springgreen + \li #00ff7f + \li \svgcolor {#00ff7f} +\row + \li steelblue + \li #4682b4 + \li \svgcolor {#4682b4} +\row + \li tan + \li #d2b48c + \li \svgcolor {#d2b48c} +\row + \li teal + \li #008080 + \li \svgcolor {#008080} +\row + \li thistle + \li #d8bfd8 + \li \svgcolor {#d8bfd8} +\row + \li tomato + \li #ff6347 + \li \svgcolor {#ff6347} +\row + \li turquoise + \li #40e0d0 + \li \svgcolor {#40e0d0} +\row + \li violet + \li #ee82ee + \li \svgcolor {#ee82ee} +\row + \li wheat + \li #f5deb3 + \li \svgcolor {#f5deb3} +\row + \li white + \li #ffffff + \li \svgcolor {#ffffff} +\row + \li whitesmoke + \li #f5f5f5 + \li \svgcolor {#f5f5f5} +\row + \li yellow + \li #ffff00 + \li \svgcolor {#ffff00} +\row + \li yellowgreen + \li #9acd32 + \li \svgcolor {#9acd32} +\endtable diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index 6cbc30e79a..8780cce223 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -147,6 +147,7 @@ static bool get_hex_rgb(const QChar *str, size_t len, QRgba64 *rgb) #endif #define rgb(r,g,b) (0xff000000 | (r << 16) | (g << 8) | b) +// keep this is in sync with QColorConstants static const struct RGBData { const char name[21]; uint value; @@ -475,25 +476,35 @@ static QStringList get_colornames() \section1 Predefined Colors - There are 20 predefined QColors described by the Qt::GlobalColor enum, - including black, white, primary and secondary colors, darker versions - of these colors and three shades of gray. QColor also recognizes a - variety of color names; the static colorNames() function returns a - QStringList color names that QColor knows about. + There are 20 predefined QColor objects in the \c{QColorConstants} + namespace, including black, white, primary and secondary colors, + darker versions of these colors, and three shades of gray. + Furthermore, the \c{QColorConstants::Svg} namespace defines QColor + objects for the standard \l{https://www.w3.org/TR/SVG11/types.html#ColorKeywords}{SVG color keyword names}. \image qt-colors.png Qt Colors - Additionally, the Qt::color0, Qt::color1 and Qt::transparent colors - are used for special purposes. + The \c{QColorConstants::Color0}, \c{QColorConstants::Color1} and + \c{QColorConstants::Transparent} colors are used for special + purposes. - Qt::color0 (zero pixel value) and Qt::color1 (non-zero pixel value) - are special colors for drawing in QBitmaps. Painting with Qt::color0 - sets the bitmap bits to 0 (transparent; i.e., background), and painting - with Qt::color1 sets the bits to 1 (opaque; i.e., foreground). + \c{QColorConstants::Color0} (zero pixel value) and + \c{QColorConstants::Color1} (non-zero pixel value) are special + colors for drawing in QBitmaps. Painting with + \c{QColorConstants::Color0} sets the bitmap bits to 0 (transparent; + i.e., background), and painting with c{QColorConstants::Color1} + sets the bits to 1 (opaque; i.e., foreground). - Qt::transparent is used to indicate a transparent pixel. When painting - with this value, a pixel value will be used that is appropriate for the - underlying pixel format in use. + \c{QColorConstants::Transparent} is used to indicate a transparent + pixel. When painting with this value, a pixel value will be used + that is appropriate for the underlying pixel format in use. + + For historical reasons, the 20 predefined colors are also available + in the Qt::GlobalColor enumeration. + + Finally, QColor recognizes a variety of color names (as strings); + the static colorNames() function returns a QStringList color names + that QColor knows about. \section1 The Extended RGB Color Model @@ -586,7 +597,7 @@ static QStringList get_colornames() alpha-channel to feature \l {QColor#Alpha-Blended Drawing}{alpha-blended drawing}. - \sa QPalette, QBrush + \sa QPalette, QBrush, QColorConstants */ #define QCOLOR_INT_RANGE_CHECK(fn, var) \ @@ -886,7 +897,8 @@ QString QColor::name(NameFormat format) const \li #AARRGGBB (Since 5.2) \li #RRRGGGBBB \li #RRRRGGGGBBBB - \li A name from the list of colors defined in the list of \l{http://www.w3.org/TR/SVG/types.html#ColorKeywords}{SVG color keyword names} + \li A name from the list of colors defined in the list of + \l{https://www.w3.org/TR/SVG11/types.html#ColorKeywords}{SVG color keyword names} provided by the World Wide Web Consortium; for example, "steelblue" or "gainsboro". These color names work on all platforms. Note that these color names are \e not the same as defined by the Qt::GlobalColor enums, e.g. "green" and Qt::green does not @@ -3249,4 +3261,41 @@ const uint qt_inv_premul_factor[256] = { \sa QColor::rgb(), QColor::rgba() */ +/*! + \namespace QColorConstants + \inmodule QtGui + + \brief The QColorConstants namespace contains QColor predefined constants. + + These constants are usable everywhere a QColor object is expected: + + \code + painter.setBrush(QColorConstants::Svg::lightblue); + \endcode + + Their usage is much cheaper than e.g. passing a string to QColor's constructor, + as they don't require any parsing of the string, and always result in a valid + QColor object: + + \badcode + object.setColor(QColor("lightblue")); // expensive + \endcode + + \section1 Qt Colors + + The following colors are defined in the \c{QColorConstants} namespace: + + \include qt-colors.qdocinc + + \section1 SVG Colors + + The following table lists the available + \l {http://www.w3.org/TR/SVG/types.html#ColorKeywords}{SVG colors}. + They are available in the \c{QColorConstants::Svg} inner namespace. + + \include svg-colors.qdocinc + + \sa QColor, Qt::GlobalColor +*/ + QT_END_NAMESPACE diff --git a/src/gui/painting/qcolor.h b/src/gui/painting/qcolor.h index 723b9fce73..f0d7dd23ad 100644 --- a/src/gui/painting/qcolor.h +++ b/src/gui/painting/qcolor.h @@ -309,6 +309,12 @@ private: friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QColor &); friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QColor &); #endif + +#ifdef Q_COMPILER_UNIFORM_INIT +public: // can't give friendship to a namespace, so it needs to be public + Q_DECL_CONSTEXPR explicit QColor(Spec spec, ushort a1, ushort a2, ushort a3, ushort a4, ushort a5=0) noexcept + : cspec(spec), ct(a1, a2, a3, a4, a5) {} +#endif // Q_COMPILER_UNIFORM_INIT }; Q_DECLARE_TYPEINFO(QColor, QT_VERSION >= QT_VERSION_CHECK(6,0,0) ? Q_MOVABLE_TYPE : Q_RELOCATABLE_TYPE); @@ -326,6 +332,187 @@ inline QColor::QColor(const QString& aname) inline bool QColor::isValid() const noexcept { return cspec != Invalid; } +// define these namespaces even if the contents are ifdef'd out +namespace QColorConstants +{ +namespace Svg {} + +#if defined(Q_COMPILER_CONSTEXPR) & defined(Q_COMPILER_UNIFORM_INIT) + // Qt::GlobalColor names + constexpr Q_DECL_UNUSED QColor Color0 {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor Color1 {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101}; + constexpr Q_DECL_UNUSED QColor Black {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor White {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101}; + constexpr Q_DECL_UNUSED QColor DarkGray {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x80 * 0x101, 0x80 * 0x101}; + constexpr Q_DECL_UNUSED QColor Gray {QColor::Rgb, 0xff * 0x101, 0xa0 * 0x101, 0xa0 * 0x101, 0xa4 * 0x101}; + constexpr Q_DECL_UNUSED QColor LightGray {QColor::Rgb, 0xff * 0x101, 0xc0 * 0x101, 0xc0 * 0x101, 0xc0 * 0x101}; + constexpr Q_DECL_UNUSED QColor Red {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor Green {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor Blue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0xff * 0x101}; + constexpr Q_DECL_UNUSED QColor Cyan {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0xff * 0x101}; + constexpr Q_DECL_UNUSED QColor Magenta {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101}; + constexpr Q_DECL_UNUSED QColor Yellow {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor DarkRed {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x00 * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor DarkGreen {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x80 * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor DarkBlue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x80 * 0x101}; + constexpr Q_DECL_UNUSED QColor DarkCyan {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x80 * 0x101, 0x80 * 0x101}; + constexpr Q_DECL_UNUSED QColor DarkMagenta {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x00 * 0x101, 0x80 * 0x101}; + constexpr Q_DECL_UNUSED QColor DarkYellow {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x80 * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor Transparent {QColor::Rgb, 0x00 * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x00 * 0x101}; + + // SVG names supported by QColor (see qcolor.cpp). +namespace Svg { + constexpr Q_DECL_UNUSED QColor aliceblue {QColor::Rgb, 0xff * 0x101, 0xf0 * 0x101, 0xf8 * 0x101, 0xff * 0x101}; + constexpr Q_DECL_UNUSED QColor antiquewhite {QColor::Rgb, 0xff * 0x101, 0xfa * 0x101, 0xeb * 0x101, 0xd7 * 0x101}; + constexpr Q_DECL_UNUSED QColor aqua {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0xff * 0x101}; + constexpr Q_DECL_UNUSED QColor aquamarine {QColor::Rgb, 0xff * 0x101, 0x7f * 0x101, 0xff * 0x101, 0xd4 * 0x101}; + constexpr Q_DECL_UNUSED QColor azure {QColor::Rgb, 0xff * 0x101, 0xf0 * 0x101, 0xff * 0x101, 0xff * 0x101}; + constexpr Q_DECL_UNUSED QColor beige {QColor::Rgb, 0xff * 0x101, 0xf5 * 0x101, 0xf5 * 0x101, 0xdc * 0x101}; + constexpr Q_DECL_UNUSED QColor bisque {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xe4 * 0x101, 0xc4 * 0x101}; + constexpr Q_DECL_UNUSED QColor black {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor blanchedalmond {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xeb * 0x101, 0xcd * 0x101}; + constexpr Q_DECL_UNUSED QColor blue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0xff * 0x101}; + constexpr Q_DECL_UNUSED QColor blueviolet {QColor::Rgb, 0xff * 0x101, 0x8a * 0x101, 0x2b * 0x101, 0xe2 * 0x101}; + constexpr Q_DECL_UNUSED QColor brown {QColor::Rgb, 0xff * 0x101, 0xa5 * 0x101, 0x2a * 0x101, 0x2a * 0x101}; + constexpr Q_DECL_UNUSED QColor burlywood {QColor::Rgb, 0xff * 0x101, 0xde * 0x101, 0xb8 * 0x101, 0x87 * 0x101}; + constexpr Q_DECL_UNUSED QColor cadetblue {QColor::Rgb, 0xff * 0x101, 0x5f * 0x101, 0x9e * 0x101, 0xa0 * 0x101}; + constexpr Q_DECL_UNUSED QColor chartreuse {QColor::Rgb, 0xff * 0x101, 0x7f * 0x101, 0xff * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor chocolate {QColor::Rgb, 0xff * 0x101, 0xd2 * 0x101, 0x69 * 0x101, 0x1e * 0x101}; + constexpr Q_DECL_UNUSED QColor coral {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x7f * 0x101, 0x50 * 0x101}; + constexpr Q_DECL_UNUSED QColor cornflowerblue {QColor::Rgb, 0xff * 0x101, 0x64 * 0x101, 0x95 * 0x101, 0xed * 0x101}; + constexpr Q_DECL_UNUSED QColor cornsilk {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xf8 * 0x101, 0xdc * 0x101}; + constexpr Q_DECL_UNUSED QColor crimson {QColor::Rgb, 0xff * 0x101, 0xdc * 0x101, 0x14 * 0x101, 0x3c * 0x101}; + constexpr Q_DECL_UNUSED QColor cyan {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0xff * 0x101}; + constexpr Q_DECL_UNUSED QColor darkblue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x8b * 0x101}; + constexpr Q_DECL_UNUSED QColor darkcyan {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x8b * 0x101, 0x8b * 0x101}; + constexpr Q_DECL_UNUSED QColor darkgoldenrod {QColor::Rgb, 0xff * 0x101, 0xb8 * 0x101, 0x86 * 0x101, 0x0b * 0x101}; + constexpr Q_DECL_UNUSED QColor darkgray {QColor::Rgb, 0xff * 0x101, 0xa9 * 0x101, 0xa9 * 0x101, 0xa9 * 0x101}; + constexpr Q_DECL_UNUSED QColor darkgreen {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x64 * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor darkgrey {QColor::Rgb, 0xff * 0x101, 0xa9 * 0x101, 0xa9 * 0x101, 0xa9 * 0x101}; + constexpr Q_DECL_UNUSED QColor darkkhaki {QColor::Rgb, 0xff * 0x101, 0xbd * 0x101, 0xb7 * 0x101, 0x6b * 0x101}; + constexpr Q_DECL_UNUSED QColor darkmagenta {QColor::Rgb, 0xff * 0x101, 0x8b * 0x101, 0x00 * 0x101, 0x8b * 0x101}; + constexpr Q_DECL_UNUSED QColor darkolivegreen {QColor::Rgb, 0xff * 0x101, 0x55 * 0x101, 0x6b * 0x101, 0x2f * 0x101}; + constexpr Q_DECL_UNUSED QColor darkorange {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x8c * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor darkorchid {QColor::Rgb, 0xff * 0x101, 0x99 * 0x101, 0x32 * 0x101, 0xcc * 0x101}; + constexpr Q_DECL_UNUSED QColor darkred {QColor::Rgb, 0xff * 0x101, 0x8b * 0x101, 0x00 * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor darksalmon {QColor::Rgb, 0xff * 0x101, 0xe9 * 0x101, 0x96 * 0x101, 0x7a * 0x101}; + constexpr Q_DECL_UNUSED QColor darkseagreen {QColor::Rgb, 0xff * 0x101, 0x8f * 0x101, 0xbc * 0x101, 0x8f * 0x101}; + constexpr Q_DECL_UNUSED QColor darkslateblue {QColor::Rgb, 0xff * 0x101, 0x48 * 0x101, 0x3d * 0x101, 0x8b * 0x101}; + constexpr Q_DECL_UNUSED QColor darkslategray {QColor::Rgb, 0xff * 0x101, 0x2f * 0x101, 0x4f * 0x101, 0x4f * 0x101}; + constexpr Q_DECL_UNUSED QColor darkslategrey {QColor::Rgb, 0xff * 0x101, 0x2f * 0x101, 0x4f * 0x101, 0x4f * 0x101}; + constexpr Q_DECL_UNUSED QColor darkturquoise {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xce * 0x101, 0xd1 * 0x101}; + constexpr Q_DECL_UNUSED QColor darkviolet {QColor::Rgb, 0xff * 0x101, 0x94 * 0x101, 0x00 * 0x101, 0xd3 * 0x101}; + constexpr Q_DECL_UNUSED QColor deeppink {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x14 * 0x101, 0x93 * 0x101}; + constexpr Q_DECL_UNUSED QColor deepskyblue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xbf * 0x101, 0xff * 0x101}; + constexpr Q_DECL_UNUSED QColor dimgray {QColor::Rgb, 0xff * 0x101, 0x69 * 0x101, 0x69 * 0x101, 0x69 * 0x101}; + constexpr Q_DECL_UNUSED QColor dimgrey {QColor::Rgb, 0xff * 0x101, 0x69 * 0x101, 0x69 * 0x101, 0x69 * 0x101}; + constexpr Q_DECL_UNUSED QColor dodgerblue {QColor::Rgb, 0xff * 0x101, 0x1e * 0x101, 0x90 * 0x101, 0xff * 0x101}; + constexpr Q_DECL_UNUSED QColor firebrick {QColor::Rgb, 0xff * 0x101, 0xb2 * 0x101, 0x22 * 0x101, 0x22 * 0x101}; + constexpr Q_DECL_UNUSED QColor floralwhite {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xfa * 0x101, 0xf0 * 0x101}; + constexpr Q_DECL_UNUSED QColor forestgreen {QColor::Rgb, 0xff * 0x101, 0x22 * 0x101, 0x8b * 0x101, 0x22 * 0x101}; + constexpr Q_DECL_UNUSED QColor fuchsia {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101}; + constexpr Q_DECL_UNUSED QColor gainsboro {QColor::Rgb, 0xff * 0x101, 0xdc * 0x101, 0xdc * 0x101, 0xdc * 0x101}; + constexpr Q_DECL_UNUSED QColor ghostwhite {QColor::Rgb, 0xff * 0x101, 0xf8 * 0x101, 0xf8 * 0x101, 0xff * 0x101}; + constexpr Q_DECL_UNUSED QColor gold {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xd7 * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor goldenrod {QColor::Rgb, 0xff * 0x101, 0xda * 0x101, 0xa5 * 0x101, 0x20 * 0x101}; + constexpr Q_DECL_UNUSED QColor gray {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x80 * 0x101, 0x80 * 0x101}; + constexpr Q_DECL_UNUSED QColor green {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x80 * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor greenyellow {QColor::Rgb, 0xff * 0x101, 0xad * 0x101, 0xff * 0x101, 0x2f * 0x101}; + constexpr Q_DECL_UNUSED QColor grey {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x80 * 0x101, 0x80 * 0x101}; + constexpr Q_DECL_UNUSED QColor honeydew {QColor::Rgb, 0xff * 0x101, 0xf0 * 0x101, 0xff * 0x101, 0xf0 * 0x101}; + constexpr Q_DECL_UNUSED QColor hotpink {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x69 * 0x101, 0xb4 * 0x101}; + constexpr Q_DECL_UNUSED QColor indianred {QColor::Rgb, 0xff * 0x101, 0xcd * 0x101, 0x5c * 0x101, 0x5c * 0x101}; + constexpr Q_DECL_UNUSED QColor indigo {QColor::Rgb, 0xff * 0x101, 0x4b * 0x101, 0x00 * 0x101, 0x82 * 0x101}; + constexpr Q_DECL_UNUSED QColor ivory {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0xf0 * 0x101}; + constexpr Q_DECL_UNUSED QColor khaki {QColor::Rgb, 0xff * 0x101, 0xf0 * 0x101, 0xe6 * 0x101, 0x8c * 0x101}; + constexpr Q_DECL_UNUSED QColor lavender {QColor::Rgb, 0xff * 0x101, 0xe6 * 0x101, 0xe6 * 0x101, 0xfa * 0x101}; + constexpr Q_DECL_UNUSED QColor lavenderblush {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xf0 * 0x101, 0xf5 * 0x101}; + constexpr Q_DECL_UNUSED QColor lawngreen {QColor::Rgb, 0xff * 0x101, 0x7c * 0x101, 0xfc * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor lemonchiffon {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xfa * 0x101, 0xcd * 0x101}; + constexpr Q_DECL_UNUSED QColor lightblue {QColor::Rgb, 0xff * 0x101, 0xad * 0x101, 0xd8 * 0x101, 0xe6 * 0x101}; + constexpr Q_DECL_UNUSED QColor lightcoral {QColor::Rgb, 0xff * 0x101, 0xf0 * 0x101, 0x80 * 0x101, 0x80 * 0x101}; + constexpr Q_DECL_UNUSED QColor lightcyan {QColor::Rgb, 0xff * 0x101, 0xe0 * 0x101, 0xff * 0x101, 0xff * 0x101}; + constexpr Q_DECL_UNUSED QColor lightgoldenrodyellow {QColor::Rgb, 0xff * 0x101, 0xfa * 0x101, 0xfa * 0x101, 0xd2 * 0x101}; + constexpr Q_DECL_UNUSED QColor lightgray {QColor::Rgb, 0xff * 0x101, 0xd3 * 0x101, 0xd3 * 0x101, 0xd3 * 0x101}; + constexpr Q_DECL_UNUSED QColor lightgreen {QColor::Rgb, 0xff * 0x101, 0x90 * 0x101, 0xee * 0x101, 0x90 * 0x101}; + constexpr Q_DECL_UNUSED QColor lightgrey {QColor::Rgb, 0xff * 0x101, 0xd3 * 0x101, 0xd3 * 0x101, 0xd3 * 0x101}; + constexpr Q_DECL_UNUSED QColor lightpink {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xb6 * 0x101, 0xc1 * 0x101}; + constexpr Q_DECL_UNUSED QColor lightsalmon {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xa0 * 0x101, 0x7a * 0x101}; + constexpr Q_DECL_UNUSED QColor lightseagreen {QColor::Rgb, 0xff * 0x101, 0x20 * 0x101, 0xb2 * 0x101, 0xaa * 0x101}; + constexpr Q_DECL_UNUSED QColor lightskyblue {QColor::Rgb, 0xff * 0x101, 0x87 * 0x101, 0xce * 0x101, 0xfa * 0x101}; + constexpr Q_DECL_UNUSED QColor lightslategray {QColor::Rgb, 0xff * 0x101, 0x77 * 0x101, 0x88 * 0x101, 0x99 * 0x101}; + constexpr Q_DECL_UNUSED QColor lightslategrey {QColor::Rgb, 0xff * 0x101, 0x77 * 0x101, 0x88 * 0x101, 0x99 * 0x101}; + constexpr Q_DECL_UNUSED QColor lightsteelblue {QColor::Rgb, 0xff * 0x101, 0xb0 * 0x101, 0xc4 * 0x101, 0xde * 0x101}; + constexpr Q_DECL_UNUSED QColor lightyellow {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0xe0 * 0x101}; + constexpr Q_DECL_UNUSED QColor lime {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor limegreen {QColor::Rgb, 0xff * 0x101, 0x32 * 0x101, 0xcd * 0x101, 0x32 * 0x101}; + constexpr Q_DECL_UNUSED QColor linen {QColor::Rgb, 0xff * 0x101, 0xfa * 0x101, 0xf0 * 0x101, 0xe6 * 0x101}; + constexpr Q_DECL_UNUSED QColor magenta {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101}; + constexpr Q_DECL_UNUSED QColor maroon {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x00 * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor mediumaquamarine {QColor::Rgb, 0xff * 0x101, 0x66 * 0x101, 0xcd * 0x101, 0xaa * 0x101}; + constexpr Q_DECL_UNUSED QColor mediumblue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0xcd * 0x101}; + constexpr Q_DECL_UNUSED QColor mediumorchid {QColor::Rgb, 0xff * 0x101, 0xba * 0x101, 0x55 * 0x101, 0xd3 * 0x101}; + constexpr Q_DECL_UNUSED QColor mediumpurple {QColor::Rgb, 0xff * 0x101, 0x93 * 0x101, 0x70 * 0x101, 0xdb * 0x101}; + constexpr Q_DECL_UNUSED QColor mediumseagreen {QColor::Rgb, 0xff * 0x101, 0x3c * 0x101, 0xb3 * 0x101, 0x71 * 0x101}; + constexpr Q_DECL_UNUSED QColor mediumslateblue {QColor::Rgb, 0xff * 0x101, 0x7b * 0x101, 0x68 * 0x101, 0xee * 0x101}; + constexpr Q_DECL_UNUSED QColor mediumspringgreen {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xfa * 0x101, 0x9a * 0x101}; + constexpr Q_DECL_UNUSED QColor mediumturquoise {QColor::Rgb, 0xff * 0x101, 0x48 * 0x101, 0xd1 * 0x101, 0xcc * 0x101}; + constexpr Q_DECL_UNUSED QColor mediumvioletred {QColor::Rgb, 0xff * 0x101, 0xc7 * 0x101, 0x15 * 0x101, 0x85 * 0x101}; + constexpr Q_DECL_UNUSED QColor midnightblue {QColor::Rgb, 0xff * 0x101, 0x19 * 0x101, 0x19 * 0x101, 0x70 * 0x101}; + constexpr Q_DECL_UNUSED QColor mintcream {QColor::Rgb, 0xff * 0x101, 0xf5 * 0x101, 0xff * 0x101, 0xfa * 0x101}; + constexpr Q_DECL_UNUSED QColor mistyrose {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xe4 * 0x101, 0xe1 * 0x101}; + constexpr Q_DECL_UNUSED QColor moccasin {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xe4 * 0x101, 0xb5 * 0x101}; + constexpr Q_DECL_UNUSED QColor navajowhite {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xde * 0x101, 0xad * 0x101}; + constexpr Q_DECL_UNUSED QColor navy {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x80 * 0x101}; + constexpr Q_DECL_UNUSED QColor oldlace {QColor::Rgb, 0xff * 0x101, 0xfd * 0x101, 0xf5 * 0x101, 0xe6 * 0x101}; + constexpr Q_DECL_UNUSED QColor olive {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x80 * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor olivedrab {QColor::Rgb, 0xff * 0x101, 0x6b * 0x101, 0x8e * 0x101, 0x23 * 0x101}; + constexpr Q_DECL_UNUSED QColor orange {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xa5 * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor orangered {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x45 * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor orchid {QColor::Rgb, 0xff * 0x101, 0xda * 0x101, 0x70 * 0x101, 0xd6 * 0x101}; + constexpr Q_DECL_UNUSED QColor palegoldenrod {QColor::Rgb, 0xff * 0x101, 0xee * 0x101, 0xe8 * 0x101, 0xaa * 0x101}; + constexpr Q_DECL_UNUSED QColor palegreen {QColor::Rgb, 0xff * 0x101, 0x98 * 0x101, 0xfb * 0x101, 0x98 * 0x101}; + constexpr Q_DECL_UNUSED QColor paleturquoise {QColor::Rgb, 0xff * 0x101, 0xaf * 0x101, 0xee * 0x101, 0xee * 0x101}; + constexpr Q_DECL_UNUSED QColor palevioletred {QColor::Rgb, 0xff * 0x101, 0xdb * 0x101, 0x70 * 0x101, 0x93 * 0x101}; + constexpr Q_DECL_UNUSED QColor papayawhip {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xef * 0x101, 0xd5 * 0x101}; + constexpr Q_DECL_UNUSED QColor peachpuff {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xda * 0x101, 0xb9 * 0x101}; + constexpr Q_DECL_UNUSED QColor peru {QColor::Rgb, 0xff * 0x101, 0xcd * 0x101, 0x85 * 0x101, 0x3f * 0x101}; + constexpr Q_DECL_UNUSED QColor pink {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xc0 * 0x101, 0xcb * 0x101}; + constexpr Q_DECL_UNUSED QColor plum {QColor::Rgb, 0xff * 0x101, 0xdd * 0x101, 0xa0 * 0x101, 0xdd * 0x101}; + constexpr Q_DECL_UNUSED QColor powderblue {QColor::Rgb, 0xff * 0x101, 0xb0 * 0x101, 0xe0 * 0x101, 0xe6 * 0x101}; + constexpr Q_DECL_UNUSED QColor purple {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x00 * 0x101, 0x80 * 0x101}; + constexpr Q_DECL_UNUSED QColor red {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor rosybrown {QColor::Rgb, 0xff * 0x101, 0xbc * 0x101, 0x8f * 0x101, 0x8f * 0x101}; + constexpr Q_DECL_UNUSED QColor royalblue {QColor::Rgb, 0xff * 0x101, 0x41 * 0x101, 0x69 * 0x101, 0xe1 * 0x101}; + constexpr Q_DECL_UNUSED QColor saddlebrown {QColor::Rgb, 0xff * 0x101, 0x8b * 0x101, 0x45 * 0x101, 0x13 * 0x101}; + constexpr Q_DECL_UNUSED QColor salmon {QColor::Rgb, 0xff * 0x101, 0xfa * 0x101, 0x80 * 0x101, 0x72 * 0x101}; + constexpr Q_DECL_UNUSED QColor sandybrown {QColor::Rgb, 0xff * 0x101, 0xf4 * 0x101, 0xa4 * 0x101, 0x60 * 0x101}; + constexpr Q_DECL_UNUSED QColor seagreen {QColor::Rgb, 0xff * 0x101, 0x2e * 0x101, 0x8b * 0x101, 0x57 * 0x101}; + constexpr Q_DECL_UNUSED QColor seashell {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xf5 * 0x101, 0xee * 0x101}; + constexpr Q_DECL_UNUSED QColor sienna {QColor::Rgb, 0xff * 0x101, 0xa0 * 0x101, 0x52 * 0x101, 0x2d * 0x101}; + constexpr Q_DECL_UNUSED QColor silver {QColor::Rgb, 0xff * 0x101, 0xc0 * 0x101, 0xc0 * 0x101, 0xc0 * 0x101}; + constexpr Q_DECL_UNUSED QColor skyblue {QColor::Rgb, 0xff * 0x101, 0x87 * 0x101, 0xce * 0x101, 0xeb * 0x101}; + constexpr Q_DECL_UNUSED QColor slateblue {QColor::Rgb, 0xff * 0x101, 0x6a * 0x101, 0x5a * 0x101, 0xcd * 0x101}; + constexpr Q_DECL_UNUSED QColor slategray {QColor::Rgb, 0xff * 0x101, 0x70 * 0x101, 0x80 * 0x101, 0x90 * 0x101}; + constexpr Q_DECL_UNUSED QColor slategrey {QColor::Rgb, 0xff * 0x101, 0x70 * 0x101, 0x80 * 0x101, 0x90 * 0x101}; + constexpr Q_DECL_UNUSED QColor snow {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xfa * 0x101, 0xfa * 0x101}; + constexpr Q_DECL_UNUSED QColor springgreen {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0x7f * 0x101}; + constexpr Q_DECL_UNUSED QColor steelblue {QColor::Rgb, 0xff * 0x101, 0x46 * 0x101, 0x82 * 0x101, 0xb4 * 0x101}; + constexpr Q_DECL_UNUSED QColor tan {QColor::Rgb, 0xff * 0x101, 0xd2 * 0x101, 0xb4 * 0x101, 0x8c * 0x101}; + constexpr Q_DECL_UNUSED QColor teal {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x80 * 0x101, 0x80 * 0x101}; + constexpr Q_DECL_UNUSED QColor thistle {QColor::Rgb, 0xff * 0x101, 0xd8 * 0x101, 0xbf * 0x101, 0xd8 * 0x101}; + constexpr Q_DECL_UNUSED QColor tomato {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x63 * 0x101, 0x47 * 0x101}; + constexpr Q_DECL_UNUSED QColor turquoise {QColor::Rgb, 0xff * 0x101, 0x40 * 0x101, 0xe0 * 0x101, 0xd0 * 0x101}; + constexpr Q_DECL_UNUSED QColor violet {QColor::Rgb, 0xff * 0x101, 0xee * 0x101, 0x82 * 0x101, 0xee * 0x101}; + constexpr Q_DECL_UNUSED QColor wheat {QColor::Rgb, 0xff * 0x101, 0xf5 * 0x101, 0xde * 0x101, 0xb3 * 0x101}; + constexpr Q_DECL_UNUSED QColor white {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101}; + constexpr Q_DECL_UNUSED QColor whitesmoke {QColor::Rgb, 0xff * 0x101, 0xf5 * 0x101, 0xf5 * 0x101, 0xf5 * 0x101}; + constexpr Q_DECL_UNUSED QColor yellow {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101}; + constexpr Q_DECL_UNUSED QColor yellowgreen {QColor::Rgb, 0xff * 0x101, 0x9a * 0x101, 0xcd * 0x101, 0x32 * 0x101}; +} // namespace Svg +#endif // Q_COMPILER_CONSTEXPR && Q_COMPILER_UNIFORM_INIT +} // namespace QColorLiterals + QT_END_NAMESPACE #endif // QCOLOR_H diff --git a/tests/auto/gui/painting/qcolor/tst_qcolor.cpp b/tests/auto/gui/painting/qcolor/tst_qcolor.cpp index 90a216e14a..6c66519dce 100644 --- a/tests/auto/gui/painting/qcolor/tst_qcolor.cpp +++ b/tests/auto/gui/painting/qcolor/tst_qcolor.cpp @@ -64,6 +64,10 @@ private slots: void globalColors_data(); void globalColors(); +#if defined(Q_COMPILER_CONSTEXPR) & defined(Q_COMPILER_UNIFORM_INIT) + void colorConstants_data(); + void colorConstants(); +#endif void setRed(); void setGreen(); @@ -368,6 +372,191 @@ void tst_QColor::globalColors() QCOMPARE(color.rgba(), argb); } +#if defined(Q_COMPILER_CONSTEXPR) & defined(Q_COMPILER_UNIFORM_INIT) +void tst_QColor::colorConstants_data() +{ + QTest::addColumn("color"); + QTest::addColumn("argb"); + + QTest::newRow("invalid") << QColor() << 0xff000000; + QTest::newRow("global color color0") << QColorConstants::Color0 << 0xff000000u; + QTest::newRow("global color color1") << QColorConstants::Color1 << 0xffffffffu; + QTest::newRow("global color black") << QColorConstants::Black << 0xff000000u; + QTest::newRow("global color white") << QColorConstants::White << 0xffffffffu; + QTest::newRow("global color darkGray") << QColorConstants::DarkGray << 0xff808080u; + QTest::newRow("global color gray") << QColorConstants::Gray << 0xffa0a0a4u; + QTest::newRow("global color lightGray") << QColorConstants::LightGray << 0xffc0c0c0u; + QTest::newRow("global color red") << QColorConstants::Red << 0xffff0000u; + QTest::newRow("global color green") << QColorConstants::Green << 0xff00ff00u; + QTest::newRow("global color blue") << QColorConstants::Blue << 0xff0000ffu; + QTest::newRow("global color cyan") << QColorConstants::Cyan << 0xff00ffffu; + QTest::newRow("global color magenta") << QColorConstants::Magenta << 0xffff00ffu; + QTest::newRow("global color yellow") << QColorConstants::Yellow << 0xffffff00u; + QTest::newRow("global color darkRed") << QColorConstants::DarkRed << 0xff800000u; + QTest::newRow("global color darkGreen") << QColorConstants::DarkGreen << 0xff008000u; + QTest::newRow("global color darkBlue") << QColorConstants::DarkBlue << 0xff000080u; + QTest::newRow("global color darkCyan") << QColorConstants::DarkCyan << 0xff008080u; + QTest::newRow("global color darkMagenta") << QColorConstants::DarkMagenta << 0xff800080u; + QTest::newRow("global color darkYellow") << QColorConstants::DarkYellow << 0xff808000u; + QTest::newRow("global color transparent") << QColorConstants::Transparent << 0x00000000u; + + QTest::newRow("SVG aliceblue") << QColorConstants::Svg::aliceblue << 0xfff0f8ffu; + QTest::newRow("SVG antiquewhite") << QColorConstants::Svg::antiquewhite << 0xfffaebd7u; + QTest::newRow("SVG aqua") << QColorConstants::Svg::aqua << 0xff00ffffu; + QTest::newRow("SVG aquamarine") << QColorConstants::Svg::aquamarine << 0xff7fffd4u; + QTest::newRow("SVG azure") << QColorConstants::Svg::azure << 0xfff0ffffu; + QTest::newRow("SVG beige") << QColorConstants::Svg::beige << 0xfff5f5dcu; + QTest::newRow("SVG bisque") << QColorConstants::Svg::bisque << 0xffffe4c4u; + QTest::newRow("SVG black") << QColorConstants::Svg::black << 0xff000000u; + QTest::newRow("SVG blanchedalmond") << QColorConstants::Svg::blanchedalmond << 0xffffebcdu; + QTest::newRow("SVG blue") << QColorConstants::Svg::blue << 0xff0000ffu; + QTest::newRow("SVG blueviolet") << QColorConstants::Svg::blueviolet << 0xff8a2be2u; + QTest::newRow("SVG brown") << QColorConstants::Svg::brown << 0xffa52a2au; + QTest::newRow("SVG burlywood") << QColorConstants::Svg::burlywood << 0xffdeb887u; + QTest::newRow("SVG cadetblue") << QColorConstants::Svg::cadetblue << 0xff5f9ea0u; + QTest::newRow("SVG chartreuse") << QColorConstants::Svg::chartreuse << 0xff7fff00u; + QTest::newRow("SVG chocolate") << QColorConstants::Svg::chocolate << 0xffd2691eu; + QTest::newRow("SVG coral") << QColorConstants::Svg::coral << 0xffff7f50u; + QTest::newRow("SVG cornflowerblue") << QColorConstants::Svg::cornflowerblue << 0xff6495edu; + QTest::newRow("SVG cornsilk") << QColorConstants::Svg::cornsilk << 0xfffff8dcu; + QTest::newRow("SVG crimson") << QColorConstants::Svg::crimson << 0xffdc143cu; + QTest::newRow("SVG cyan") << QColorConstants::Svg::cyan << 0xff00ffffu; + QTest::newRow("SVG darkblue") << QColorConstants::Svg::darkblue << 0xff00008bu; + QTest::newRow("SVG darkcyan") << QColorConstants::Svg::darkcyan << 0xff008b8bu; + QTest::newRow("SVG darkgoldenrod") << QColorConstants::Svg::darkgoldenrod << 0xffb8860bu; + QTest::newRow("SVG darkgray") << QColorConstants::Svg::darkgray << 0xffa9a9a9u; + QTest::newRow("SVG darkgreen") << QColorConstants::Svg::darkgreen << 0xff006400u; + QTest::newRow("SVG darkgrey") << QColorConstants::Svg::darkgrey << 0xffa9a9a9u; + QTest::newRow("SVG darkkhaki") << QColorConstants::Svg::darkkhaki << 0xffbdb76bu; + QTest::newRow("SVG darkmagenta") << QColorConstants::Svg::darkmagenta << 0xff8b008bu; + QTest::newRow("SVG darkolivegreen") << QColorConstants::Svg::darkolivegreen << 0xff556b2fu; + QTest::newRow("SVG darkorange") << QColorConstants::Svg::darkorange << 0xffff8c00u; + QTest::newRow("SVG darkorchid") << QColorConstants::Svg::darkorchid << 0xff9932ccu; + QTest::newRow("SVG darkred") << QColorConstants::Svg::darkred << 0xff8b0000u; + QTest::newRow("SVG darksalmon") << QColorConstants::Svg::darksalmon << 0xffe9967au; + QTest::newRow("SVG darkseagreen") << QColorConstants::Svg::darkseagreen << 0xff8fbc8fu; + QTest::newRow("SVG darkslateblue") << QColorConstants::Svg::darkslateblue << 0xff483d8bu; + QTest::newRow("SVG darkslategray") << QColorConstants::Svg::darkslategray << 0xff2f4f4fu; + QTest::newRow("SVG darkslategrey") << QColorConstants::Svg::darkslategrey << 0xff2f4f4fu; + QTest::newRow("SVG darkturquoise") << QColorConstants::Svg::darkturquoise << 0xff00ced1u; + QTest::newRow("SVG darkviolet") << QColorConstants::Svg::darkviolet << 0xff9400d3u; + QTest::newRow("SVG deeppink") << QColorConstants::Svg::deeppink << 0xffff1493u; + QTest::newRow("SVG deepskyblue") << QColorConstants::Svg::deepskyblue << 0xff00bfffu; + QTest::newRow("SVG dimgray") << QColorConstants::Svg::dimgray << 0xff696969u; + QTest::newRow("SVG dimgrey") << QColorConstants::Svg::dimgrey << 0xff696969u; + QTest::newRow("SVG dodgerblue") << QColorConstants::Svg::dodgerblue << 0xff1e90ffu; + QTest::newRow("SVG firebrick") << QColorConstants::Svg::firebrick << 0xffb22222u; + QTest::newRow("SVG floralwhite") << QColorConstants::Svg::floralwhite << 0xfffffaf0u; + QTest::newRow("SVG forestgreen") << QColorConstants::Svg::forestgreen << 0xff228b22u; + QTest::newRow("SVG fuchsia") << QColorConstants::Svg::fuchsia << 0xffff00ffu; + QTest::newRow("SVG gainsboro") << QColorConstants::Svg::gainsboro << 0xffdcdcdcu; + QTest::newRow("SVG ghostwhite") << QColorConstants::Svg::ghostwhite << 0xfff8f8ffu; + QTest::newRow("SVG gold") << QColorConstants::Svg::gold << 0xffffd700u; + QTest::newRow("SVG goldenrod") << QColorConstants::Svg::goldenrod << 0xffdaa520u; + QTest::newRow("SVG gray") << QColorConstants::Svg::gray << 0xff808080u; + QTest::newRow("SVG green") << QColorConstants::Svg::green << 0xff008000u; + QTest::newRow("SVG greenyellow") << QColorConstants::Svg::greenyellow << 0xffadff2fu; + QTest::newRow("SVG grey") << QColorConstants::Svg::grey << 0xff808080u; + QTest::newRow("SVG honeydew") << QColorConstants::Svg::honeydew << 0xfff0fff0u; + QTest::newRow("SVG hotpink") << QColorConstants::Svg::hotpink << 0xffff69b4u; + QTest::newRow("SVG indianred") << QColorConstants::Svg::indianred << 0xffcd5c5cu; + QTest::newRow("SVG indigo") << QColorConstants::Svg::indigo << 0xff4b0082u; + QTest::newRow("SVG ivory") << QColorConstants::Svg::ivory << 0xfffffff0u; + QTest::newRow("SVG khaki") << QColorConstants::Svg::khaki << 0xfff0e68cu; + QTest::newRow("SVG lavender") << QColorConstants::Svg::lavender << 0xffe6e6fau; + QTest::newRow("SVG lavenderblush") << QColorConstants::Svg::lavenderblush << 0xfffff0f5u; + QTest::newRow("SVG lawngreen") << QColorConstants::Svg::lawngreen << 0xff7cfc00u; + QTest::newRow("SVG lemonchiffon") << QColorConstants::Svg::lemonchiffon << 0xfffffacdu; + QTest::newRow("SVG lightblue") << QColorConstants::Svg::lightblue << 0xffadd8e6u; + QTest::newRow("SVG lightcoral") << QColorConstants::Svg::lightcoral << 0xfff08080u; + QTest::newRow("SVG lightcyan") << QColorConstants::Svg::lightcyan << 0xffe0ffffu; + QTest::newRow("SVG lightgoldenrodyellow") << QColorConstants::Svg::lightgoldenrodyellow << 0xfffafad2u; + QTest::newRow("SVG lightgray") << QColorConstants::Svg::lightgray << 0xffd3d3d3u; + QTest::newRow("SVG lightgreen") << QColorConstants::Svg::lightgreen << 0xff90ee90u; + QTest::newRow("SVG lightgrey") << QColorConstants::Svg::lightgrey << 0xffd3d3d3u; + QTest::newRow("SVG lightpink") << QColorConstants::Svg::lightpink << 0xffffb6c1u; + QTest::newRow("SVG lightsalmon") << QColorConstants::Svg::lightsalmon << 0xffffa07au; + QTest::newRow("SVG lightseagreen") << QColorConstants::Svg::lightseagreen << 0xff20b2aau; + QTest::newRow("SVG lightskyblue") << QColorConstants::Svg::lightskyblue << 0xff87cefau; + QTest::newRow("SVG lightslategray") << QColorConstants::Svg::lightslategray << 0xff778899u; + QTest::newRow("SVG lightslategrey") << QColorConstants::Svg::lightslategrey << 0xff778899u; + QTest::newRow("SVG lightsteelblue") << QColorConstants::Svg::lightsteelblue << 0xffb0c4deu; + QTest::newRow("SVG lightyellow") << QColorConstants::Svg::lightyellow << 0xffffffe0u; + QTest::newRow("SVG lime") << QColorConstants::Svg::lime << 0xff00ff00u; + QTest::newRow("SVG limegreen") << QColorConstants::Svg::limegreen << 0xff32cd32u; + QTest::newRow("SVG linen") << QColorConstants::Svg::linen << 0xfffaf0e6u; + QTest::newRow("SVG magenta") << QColorConstants::Svg::magenta << 0xffff00ffu; + QTest::newRow("SVG maroon") << QColorConstants::Svg::maroon << 0xff800000u; + QTest::newRow("SVG mediumaquamarine") << QColorConstants::Svg::mediumaquamarine << 0xff66cdaau; + QTest::newRow("SVG mediumblue") << QColorConstants::Svg::mediumblue << 0xff0000cdu; + QTest::newRow("SVG mediumorchid") << QColorConstants::Svg::mediumorchid << 0xffba55d3u; + QTest::newRow("SVG mediumpurple") << QColorConstants::Svg::mediumpurple << 0xff9370dbu; + QTest::newRow("SVG mediumseagreen") << QColorConstants::Svg::mediumseagreen << 0xff3cb371u; + QTest::newRow("SVG mediumslateblue") << QColorConstants::Svg::mediumslateblue << 0xff7b68eeu; + QTest::newRow("SVG mediumspringgreen") << QColorConstants::Svg::mediumspringgreen << 0xff00fa9au; + QTest::newRow("SVG mediumturquoise") << QColorConstants::Svg::mediumturquoise << 0xff48d1ccu; + QTest::newRow("SVG mediumvioletred") << QColorConstants::Svg::mediumvioletred << 0xffc71585u; + QTest::newRow("SVG midnightblue") << QColorConstants::Svg::midnightblue << 0xff191970u; + QTest::newRow("SVG mintcream") << QColorConstants::Svg::mintcream << 0xfff5fffau; + QTest::newRow("SVG mistyrose") << QColorConstants::Svg::mistyrose << 0xffffe4e1u; + QTest::newRow("SVG moccasin") << QColorConstants::Svg::moccasin << 0xffffe4b5u; + QTest::newRow("SVG navajowhite") << QColorConstants::Svg::navajowhite << 0xffffdeadu; + QTest::newRow("SVG navy") << QColorConstants::Svg::navy << 0xff000080u; + QTest::newRow("SVG oldlace") << QColorConstants::Svg::oldlace << 0xfffdf5e6u; + QTest::newRow("SVG olive") << QColorConstants::Svg::olive << 0xff808000u; + QTest::newRow("SVG olivedrab") << QColorConstants::Svg::olivedrab << 0xff6b8e23u; + QTest::newRow("SVG orange") << QColorConstants::Svg::orange << 0xffffa500u; + QTest::newRow("SVG orangered") << QColorConstants::Svg::orangered << 0xffff4500u; + QTest::newRow("SVG orchid") << QColorConstants::Svg::orchid << 0xffda70d6u; + QTest::newRow("SVG palegoldenrod") << QColorConstants::Svg::palegoldenrod << 0xffeee8aau; + QTest::newRow("SVG palegreen") << QColorConstants::Svg::palegreen << 0xff98fb98u; + QTest::newRow("SVG paleturquoise") << QColorConstants::Svg::paleturquoise << 0xffafeeeeu; + QTest::newRow("SVG palevioletred") << QColorConstants::Svg::palevioletred << 0xffdb7093u; + QTest::newRow("SVG papayawhip") << QColorConstants::Svg::papayawhip << 0xffffefd5u; + QTest::newRow("SVG peachpuff") << QColorConstants::Svg::peachpuff << 0xffffdab9u; + QTest::newRow("SVG peru") << QColorConstants::Svg::peru << 0xffcd853fu; + QTest::newRow("SVG pink") << QColorConstants::Svg::pink << 0xffffc0cbu; + QTest::newRow("SVG plum") << QColorConstants::Svg::plum << 0xffdda0ddu; + QTest::newRow("SVG powderblue") << QColorConstants::Svg::powderblue << 0xffb0e0e6u; + QTest::newRow("SVG purple") << QColorConstants::Svg::purple << 0xff800080u; + QTest::newRow("SVG red") << QColorConstants::Svg::red << 0xffff0000u; + QTest::newRow("SVG rosybrown") << QColorConstants::Svg::rosybrown << 0xffbc8f8fu; + QTest::newRow("SVG royalblue") << QColorConstants::Svg::royalblue << 0xff4169e1u; + QTest::newRow("SVG saddlebrown") << QColorConstants::Svg::saddlebrown << 0xff8b4513u; + QTest::newRow("SVG salmon") << QColorConstants::Svg::salmon << 0xfffa8072u; + QTest::newRow("SVG sandybrown") << QColorConstants::Svg::sandybrown << 0xfff4a460u; + QTest::newRow("SVG seagreen") << QColorConstants::Svg::seagreen << 0xff2e8b57u; + QTest::newRow("SVG seashell") << QColorConstants::Svg::seashell << 0xfffff5eeu; + QTest::newRow("SVG sienna") << QColorConstants::Svg::sienna << 0xffa0522du; + QTest::newRow("SVG silver") << QColorConstants::Svg::silver << 0xffc0c0c0u; + QTest::newRow("SVG skyblue") << QColorConstants::Svg::skyblue << 0xff87ceebu; + QTest::newRow("SVG slateblue") << QColorConstants::Svg::slateblue << 0xff6a5acdu; + QTest::newRow("SVG slategray") << QColorConstants::Svg::slategray << 0xff708090u; + QTest::newRow("SVG slategrey") << QColorConstants::Svg::slategrey << 0xff708090u; + QTest::newRow("SVG snow") << QColorConstants::Svg::snow << 0xfffffafau; + QTest::newRow("SVG springgreen") << QColorConstants::Svg::springgreen << 0xff00ff7fu; + QTest::newRow("SVG steelblue") << QColorConstants::Svg::steelblue << 0xff4682b4u; + QTest::newRow("SVG tan") << QColorConstants::Svg::tan << 0xffd2b48cu; + QTest::newRow("SVG teal") << QColorConstants::Svg::teal << 0xff008080u; + QTest::newRow("SVG thistle") << QColorConstants::Svg::thistle << 0xffd8bfd8u; + QTest::newRow("SVG tomato") << QColorConstants::Svg::tomato << 0xffff6347u; + QTest::newRow("SVG turquoise") << QColorConstants::Svg::turquoise << 0xff40e0d0u; + QTest::newRow("SVG violet") << QColorConstants::Svg::violet << 0xffee82eeu; + QTest::newRow("SVG wheat") << QColorConstants::Svg::wheat << 0xfff5deb3u; + QTest::newRow("SVG white") << QColorConstants::Svg::white << 0xffffffffu; + QTest::newRow("SVG whitesmoke") << QColorConstants::Svg::whitesmoke << 0xfff5f5f5u; + QTest::newRow("SVG yellow") << QColorConstants::Svg::yellow << 0xffffff00u; + QTest::newRow("SVG yellowgreen") << QColorConstants::Svg::yellowgreen << 0xff9acd32u; +} + +void tst_QColor::colorConstants() +{ + QFETCH(QColor, color); + QFETCH(QRgb, argb); + QCOMPARE(color.rgba(), argb); +} +#endif // defined(Q_COMPILER_CONSTEXPR) & defined(Q_COMPILER_UNIFORM_INIT) + /* CSS color names = SVG 1.0 color names + transparent (rgba(0,0,0,0)) */ -- cgit v1.2.3 From 5bb178c479a247720fbc3fbb7f06a32b725193ac Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Thu, 1 Aug 2019 08:56:59 +0300 Subject: Say hello to Android multi arch build in one go Multi arch build in one go is need to support the new .aab packaging format. By default the users apps are built for all Android ABIs: arm64-v8a armeabi-v7a x86_64 x86 The user can pass ANDROID_ABIS to qmake to filter the ABIs during development, e.g. qmake ANDROID_ABIS="arm64-v8a armeabi-v7a" will build only for arm ABIs. [ChangeLog][Android] Android multi arch build in one go, needed to support the new .aab packaging format. Change-Id: I3a64caf9621c2a195863976a62a57cdf47e6e3b5 Reviewed-by: Eskil Abrahamsen Blomfeldt --- config.tests/arch/write_info.pri | 3 - mkspecs/android-clang/qmake.conf | 107 ++- mkspecs/android-g++/qmake.conf | 40 - mkspecs/android-g++/qplatformdefs.h | 177 ---- mkspecs/common/android-base-head.conf | 71 -- mkspecs/common/android-base-tail.conf | 82 -- mkspecs/features/android/android.prf | 25 +- .../android/android_deployment_settings.prf | 36 +- mkspecs/features/android/default_pre.prf | 76 ++ mkspecs/features/android/resolve_config.prf | 10 + mkspecs/features/exclusive_builds_post.prf | 2 + mkspecs/features/qmake_use.prf | 6 +- mkspecs/features/qt_android_deps.prf | 6 +- mkspecs/features/qt_configure.prf | 2 +- mkspecs/features/qt_functions.prf | 3 +- mkspecs/features/qt_helper_lib.prf | 33 +- mkspecs/features/qt_module_pris.prf | 27 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- src/android/jar/jar.pro | 1 + src/android/java/java.pro | 2 + .../qtproject/qt5/android/bindings/QtLoader.java | 77 +- src/android/templates/AndroidManifest.xml | 5 +- src/android/templates/build.gradle | 2 +- src/android/templates/res/values/libs.xml | 9 +- src/android/templates/templates.pro | 2 + src/corelib/corelib.pro | 1 + src/corelib/plugin/qlibrary_unix.cpp | 10 + src/gui/image/image.pri | 19 +- src/gui/painting/painting.pri | 42 +- src/plugins/bearer/android/jar/jar.pro | 2 + src/tools/androiddeployqt/main.cpp | 922 ++++++++++----------- 31 files changed, 822 insertions(+), 980 deletions(-) delete mode 100644 mkspecs/android-g++/qmake.conf delete mode 100644 mkspecs/android-g++/qplatformdefs.h delete mode 100644 mkspecs/common/android-base-head.conf delete mode 100644 mkspecs/common/android-base-tail.conf create mode 100644 mkspecs/features/android/default_pre.prf create mode 100644 mkspecs/features/android/resolve_config.prf diff --git a/config.tests/arch/write_info.pri b/config.tests/arch/write_info.pri index 79f980c873..666b9e5cbb 100644 --- a/config.tests/arch/write_info.pri +++ b/config.tests/arch/write_info.pri @@ -3,9 +3,6 @@ targetinfofile ~= s/pro$/target.txt/ win32 { ext = .exe -} else:android { - file_prefix = lib - ext = .so } else:wasm { equals(WASM_OBJECT_FILES, 1): \ ext = .o diff --git a/mkspecs/android-clang/qmake.conf b/mkspecs/android-clang/qmake.conf index 84ad884710..8252f400a1 100644 --- a/mkspecs/android-clang/qmake.conf +++ b/mkspecs/android-clang/qmake.conf @@ -8,35 +8,102 @@ CONFIG += android_install unversioned_soname unversioned_libname include(../common/linux.conf) include(../common/gcc-base-unix.conf) include(../common/clang.conf) -include(../common/android-base-head.conf) + +load(device_config) + +# In early configure setup; nothing useful to be done here. +isEmpty(DEFAULT_ANDROID_NDK_ROOT): return() + +NDK_ROOT = $$(ANDROID_NDK_ROOT) +isEmpty(NDK_ROOT): NDK_ROOT = $$DEFAULT_ANDROID_NDK_ROOT + +!exists($$NDK_ROOT): error("You need to set the ANDROID_NDK_ROOT environment variable to point to your Android NDK.") + +NDK_HOST = $$(ANDROID_NDK_HOST) +isEmpty(NDK_HOST): NDK_HOST = $$DEFAULT_ANDROID_NDK_HOST + +ANDROID_PLATFORM = $$(ANDROID_NDK_PLATFORM) +isEmpty(ANDROID_PLATFORM): ANDROID_PLATFORM = $$DEFAULT_ANDROID_PLATFORM + +ANDROID_SDK_ROOT = $$(ANDROID_SDK_ROOT) +isEmpty(ANDROID_SDK_ROOT): ANDROID_SDK_ROOT = $$DEFAULT_ANDROID_SDK_ROOT + +ANDROID_SDK_BUILD_TOOLS_REVISION = $$(ANDROID_BUILD_TOOLS_REVISION) +isEmpty(ANDROID_SDK_BUILD_TOOLS_REVISION) { + SDK_BUILD_TOOLS_REVISIONS = $$files($$ANDROID_SDK_ROOT/build-tools/*) + for (REVISION, SDK_BUILD_TOOLS_REVISIONS) { + BASENAME = $$basename(REVISION) + greaterThan(BASENAME, $$ANDROID_SDK_BUILD_TOOLS_REVISION): ANDROID_SDK_BUILD_TOOLS_REVISION = $$BASENAME + } +} + +ALL_ANDROID_ABIS = arm64-v8a armeabi-v7a x86_64 x86 + +CONFIG += $$ANDROID_PLATFORM + +QMAKE_PCH_OUTPUT_EXT = .gch + +QMAKE_CFLAGS_PRECOMPILE = -x c-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} +QMAKE_CFLAGS_USE_PRECOMPILE = -include ${QMAKE_PCH_OUTPUT_BASE} +QMAKE_CXXFLAGS_PRECOMPILE = -x c++-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} +QMAKE_CXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE NDK_LLVM_PATH = $$NDK_ROOT/toolchains/llvm/prebuilt/$$NDK_HOST QMAKE_CC = $$NDK_LLVM_PATH/bin/clang QMAKE_CXX = $$NDK_LLVM_PATH/bin/clang++ +QMAKE_LINK = $$QMAKE_CXX -# Follow https://android.googlesource.com/platform/ndk/+/ndk-release-r20/docs/BuildSystemMaintainers.md +QMAKE_CFLAGS_OPTIMIZE = -Oz +QMAKE_CFLAGS_OPTIMIZE_FULL = -Oz -equals(ANDROID_TARGET_ARCH, armeabi-v7a): \ - QMAKE_CFLAGS = -target armv7a-linux-androideabi$$replace(ANDROID_PLATFORM, "android-", "") -else: equals(ANDROID_TARGET_ARCH, arm64-v8a): \ - QMAKE_CFLAGS = -target aarch64-linux-android$$replace(ANDROID_PLATFORM, "android-", "") -else: equals(ANDROID_TARGET_ARCH, x86): \ - QMAKE_CFLAGS = -target i686-linux-android$$replace(ANDROID_PLATFORM, "android-", "") -mstackrealign -else: equals(ANDROID_TARGET_ARCH, x86_64): \ - QMAKE_CFLAGS = -target x86_64-linux-android$$replace(ANDROID_PLATFORM, "android-", "") +QMAKE_CFLAGS_WARN_ON = -Wall -W +QMAKE_CFLAGS_WARN_OFF = +QMAKE_CFLAGS_SHLIB = -fPIC +QMAKE_CFLAGS_YACC = -Wno-unused -Wno-parentheses +QMAKE_CFLAGS_THREAD = -D_REENTRANT +QMAKE_CFLAGS_HIDESYMS = -fvisibility=hidden +QMAKE_CFLAGS_NEON = -mfpu=neon -QMAKE_CFLAGS += -fno-limit-debug-info +QMAKE_LFLAGS_APP = -Wl,--no-undefined -Wl,-z,noexecstack -shared +QMAKE_LFLAGS_SHLIB = -Wl,--no-undefined -Wl,-z,noexecstack -shared +QMAKE_LFLAGS_PLUGIN = $$QMAKE_LFLAGS_SHLIB +QMAKE_LFLAGS_NOUNDEF = -Wl,--no-undefined +QMAKE_LFLAGS_RPATH = -Wl,-rpath= +QMAKE_LFLAGS_RPATHLINK = -Wl,-rpath-link= -QMAKE_LINK = $$QMAKE_CXX $$QMAKE_CFLAGS - -ANDROID_STDCPP_PATH = $$NDK_LLVM_PATH/sysroot/usr/lib/$$NDK_TOOLS_PREFIX/libc++_shared.so +QMAKE_LIBS_X11 = +QMAKE_LIBS_THREAD = +QMAKE_LIBS_OPENGL = +QMAKE_INCDIR_POST = +QMAKE_INCDIR_X11 = +QMAKE_LIBDIR_X11 = +QMAKE_INCDIR_OPENGL = +QMAKE_LIBDIR_OPENGL = ANDROID_USE_LLVM = true -QMAKE_CFLAGS_OPTIMIZE_SIZE = -Oz -QMAKE_LIBDIR_POST = -QMAKE_LFLAGS = -QMAKE_LIBS_PRIVATE = -ANDROID_CXX_STL_LIBS = +armeabi-v7a.sdk = armeabi-v7a +armeabi-v7a.target = armeabi-v7a +armeabi-v7a.dir_affix = armeabi-v7a +armeabi-v7a.CONFIG = armeabi-v7a +armeabi-v7a.deployment_identifier = armeabi-v7a + +arm64-v8a.sdk = arm64-v8a +arm64-v8a.target = arm64-v8a +arm64-v8a.dir_affix = arm64-v8a +arm64-v8a.CONFIG = arm64-v8a +arm64-v8a.deployment_identifier = arm64-v8a + +x86.sdk = x86 +x86.target = x86 +x86.dir_affix = x86 +x86.CONFIG = x86 +x86.deployment_identifier = x86 + +x86_64.sdk = x86_64 +x86_64.target = x86_64 +x86_64.dir_affix = x86_64 +x86_64.CONFIG = x86_64 +x86_64.deployment_identifier = x86_64 -include(../common/android-base-tail.conf) +load(qt_config) diff --git a/mkspecs/android-g++/qmake.conf b/mkspecs/android-g++/qmake.conf deleted file mode 100644 index 451e12bc75..0000000000 --- a/mkspecs/android-g++/qmake.conf +++ /dev/null @@ -1,40 +0,0 @@ -# qmake configuration for building with android-g++ -MAKEFILE_GENERATOR = UNIX -QMAKE_PLATFORM = android -QMAKE_COMPILER = gcc - -CONFIG += android_install unversioned_soname unversioned_libname plugin_with_soname android_deployment_settings - -include(../common/linux.conf) -include(../common/gcc-base-unix.conf) -include(../common/android-base-head.conf) - -QMAKE_CC = $${CROSS_COMPILE}gcc -QMAKE_CXX = $${CROSS_COMPILE}g++ -QMAKE_LINK = $$QMAKE_CXX -QMAKE_CFLAGS = -D__ANDROID_API__=$$replace(ANDROID_PLATFORM, "android-", "") - -ANDROID_SOURCES_CXX_STL_LIBDIR = $$NDK_ROOT/sources/cxx-stl/gnu-libstdc++/$$NDK_TOOLCHAIN_VERSION/libs/$$ANDROID_TARGET_ARCH -ANDROID_STDCPP_PATH = $$ANDROID_SOURCES_CXX_STL_LIBDIR/libgnustl_shared.so -ANDROID_CXX_STL_LIBS = -lgnustl_shared -lgcc -ANDROID_USE_LLVM = false - -exists($$NDK_ROOT/sysroot/usr/include): \ - QMAKE_CFLAGS += --sysroot=$$NDK_ROOT/sysroot \ - -isystem $$NDK_ROOT/sysroot/usr/include/$$NDK_TOOLS_PREFIX -else: QMAKE_CFLAGS += --sysroot=$$ANDROID_PLATFORM_ROOT_PATH - -QMAKE_CFLAGS += -isystem $$NDK_ROOT/sources/cxx-stl/gnu-libstdc++/$$NDK_TOOLCHAIN_VERSION/include \ - -isystem $$ANDROID_SOURCES_CXX_STL_LIBDIR/include - -equals(ANDROID_TARGET_ARCH, armeabi)|equals(ANDROID_TARGET_ARCH, armeabi-v7a): \ - LIBGCC_PATH_FULL = $$system("$$QMAKE_CXX -mthumb-interwork -print-libgcc-file-name") -else: \ - LIBGCC_PATH_FULL = $$system("$$QMAKE_CXX -print-libgcc-file-name") -ANDROID_SOURCES_CXX_STL_LIBDIR += $$dirname(LIBGCC_PATH_FULL) - -QMAKE_LIBDIR_POST = $$ANDROID_SOURCES_CXX_STL_LIBDIR -QMAKE_LFLAGS = --sysroot=$$ANDROID_PLATFORM_ROOT_PATH -equals(ANDROID_TARGET_ARCH, x86_64) QMAKE_LFLAGS += -L$$ANDROID_PLATFORM_ROOT_PATH/usr/lib64 - -include(../common/android-base-tail.conf) diff --git a/mkspecs/android-g++/qplatformdefs.h b/mkspecs/android-g++/qplatformdefs.h deleted file mode 100644 index 0b92709dd5..0000000000 --- a/mkspecs/android-g++/qplatformdefs.h +++ /dev/null @@ -1,177 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the qmake spec of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPLATFORMDEFS_H -#define QPLATFORMDEFS_H - -// Get Qt defines/settings - -#include "qglobal.h" - -// Set any POSIX/XOPEN defines at the top of this file to turn on specific APIs - -// 1) need to reset default environment if _BSD_SOURCE is defined -// 2) need to specify POSIX thread interfaces explicitly in glibc 2.0 -// 3) it seems older glibc need this to include the X/Open stuff - -#include - -// We are hot - unistd.h should have turned on the specific APIs we requested - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#ifndef _GNU_SOURCE -# define _GNU_SOURCE -#endif - -#ifdef QT_LARGEFILE_SUPPORT -#define QT_STATBUF struct stat64 -#define QT_STATBUF4TSTAT struct stat64 -#define QT_STAT ::stat64 -#define QT_FSTAT ::fstat64 -#define QT_LSTAT ::lstat64 -#define QT_OPEN ::open64 -#define QT_TRUNCATE ::truncate64 -#define QT_FTRUNCATE ::ftruncate64 -#define QT_LSEEK ::lseek64 -#else -#define QT_STATBUF struct stat -#define QT_STATBUF4TSTAT struct stat -#define QT_STAT ::stat -#define QT_FSTAT ::fstat -#define QT_LSTAT ::lstat -#define QT_OPEN ::open -#define QT_TRUNCATE ::truncate -#define QT_FTRUNCATE ::ftruncate -#define QT_LSEEK ::lseek -#endif - -#ifdef QT_LARGEFILE_SUPPORT -#define QT_FOPEN ::fopen64 -#define QT_FSEEK ::fseeko64 -#define QT_FTELL ::ftello64 -#define QT_FGETPOS ::fgetpos64 -#define QT_FSETPOS ::fsetpos64 -#define QT_MMAP ::mmap64 -#define QT_FPOS_T fpos64_t -#define QT_OFF_T off64_t -#else -#define QT_FOPEN ::fopen -#define QT_FSEEK ::fseek -#define QT_FTELL ::ftell -#define QT_FGETPOS ::fgetpos -#define QT_FSETPOS ::fsetpos -#define QT_MMAP ::mmap -#define QT_FPOS_T fpos_t -#define QT_OFF_T long -#endif - -#define QT_STAT_REG S_IFREG -#define QT_STAT_DIR S_IFDIR -#define QT_STAT_MASK S_IFMT -#define QT_STAT_LNK S_IFLNK -#define QT_SOCKET_CONNECT ::connect -#define QT_SOCKET_BIND ::bind -#define QT_FILENO fileno -#define QT_CLOSE ::close -#define QT_READ ::read -#define QT_WRITE ::write -#define QT_ACCESS ::access -#define QT_GETCWD ::getcwd -#define QT_CHDIR ::chdir -#define QT_MKDIR ::mkdir -#define QT_RMDIR ::rmdir -#define QT_OPEN_LARGEFILE O_LARGEFILE -#define QT_OPEN_RDONLY O_RDONLY -#define QT_OPEN_WRONLY O_WRONLY -#define QT_OPEN_RDWR O_RDWR -#define QT_OPEN_CREAT O_CREAT -#define QT_OPEN_TRUNC O_TRUNC -#define QT_OPEN_APPEND O_APPEND -#define QT_OPEN_EXCL O_EXCL - -// Directory iteration -#define QT_DIR DIR - -#define QT_OPENDIR ::opendir -#define QT_CLOSEDIR ::closedir - -#if defined(QT_LARGEFILE_SUPPORT) \ - && defined(QT_USE_XOPEN_LFS_EXTENSIONS) \ - && !defined(QT_NO_READDIR64) -#define QT_DIRENT struct dirent64 -#define QT_READDIR ::readdir64 -#define QT_READDIR_R ::readdir64_r -#else -#define QT_DIRENT struct dirent -#define QT_READDIR ::readdir -#define QT_READDIR_R ::readdir_r -#endif - -#define QT_SOCKET_CONNECT ::connect -#define QT_SOCKET_BIND ::bind - - -#define QT_SIGNAL_RETTYPE void -#define QT_SIGNAL_ARGS int -#define QT_SIGNAL_IGNORE SIG_IGN - -#define QT_SOCKLEN_T socklen_t - -#if defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500) -#define QT_SNPRINTF ::snprintf -#define QT_VSNPRINTF ::vsnprintf -#endif - -#endif // QPLATFORMDEFS_H diff --git a/mkspecs/common/android-base-head.conf b/mkspecs/common/android-base-head.conf deleted file mode 100644 index 7335b7f4cb..0000000000 --- a/mkspecs/common/android-base-head.conf +++ /dev/null @@ -1,71 +0,0 @@ -load(device_config) - -# In early configure setup; nothing useful to be done here. -isEmpty(DEFAULT_ANDROID_NDK_ROOT): return() - -NDK_ROOT = $$(ANDROID_NDK_ROOT) -isEmpty(NDK_ROOT): NDK_ROOT = $$DEFAULT_ANDROID_NDK_ROOT - -NDK_HOST = $$(ANDROID_NDK_HOST) -isEmpty(NDK_HOST): NDK_HOST = $$DEFAULT_ANDROID_NDK_HOST - -ANDROID_PLATFORM = $$(ANDROID_NDK_PLATFORM) -isEmpty(ANDROID_PLATFORM): ANDROID_PLATFORM = $$DEFAULT_ANDROID_PLATFORM - -ANDROID_TARGET_ARCH = $$(ANDROID_TARGET_ARCH) -isEmpty(ANDROID_TARGET_ARCH): ANDROID_TARGET_ARCH = $$DEFAULT_ANDROID_TARGET_ARCH - -NDK_TOOLCHAIN_PREFIX = $$(ANDROID_NDK_TOOLCHAIN_PREFIX) -isEmpty(NDK_TOOLCHAIN_PREFIX) { - equals(ANDROID_TARGET_ARCH, x86): NDK_TOOLCHAIN_PREFIX = x86 - else: equals(ANDROID_TARGET_ARCH, x86_64): NDK_TOOLCHAIN_PREFIX = x86_64 - else: equals(ANDROID_TARGET_ARCH, arm64-v8a): NDK_TOOLCHAIN_PREFIX = aarch64-linux-android - else: NDK_TOOLCHAIN_PREFIX = arm-linux-androideabi -} - -NDK_TOOLS_PREFIX = $$(ANDROID_NDK_TOOLS_PREFIX) -isEmpty(NDK_TOOLS_PREFIX) { - equals(ANDROID_TARGET_ARCH, x86): NDK_TOOLS_PREFIX = i686-linux-android - else: equals(ANDROID_TARGET_ARCH, x86_64): NDK_TOOLS_PREFIX = x86_64-linux-android - else: equals(ANDROID_TARGET_ARCH, arm64-v8a): NDK_TOOLS_PREFIX = aarch64-linux-android - else: NDK_TOOLS_PREFIX = arm-linux-androideabi -} - -NDK_TOOLCHAIN_VERSION = $$(ANDROID_NDK_TOOLCHAIN_VERSION) -isEmpty(NDK_TOOLCHAIN_VERSION): NDK_TOOLCHAIN_VERSION = $$DEFAULT_ANDROID_NDK_TOOLCHAIN_VERSION - -equals(ANDROID_TARGET_ARCH, x86): ANDROID_ARCHITECTURE = x86 -else: equals(ANDROID_TARGET_ARCH, x86_64): ANDROID_ARCHITECTURE = x86_64 -else: equals(ANDROID_TARGET_ARCH, arm64-v8a): ANDROID_ARCHITECTURE = arm64 -else: ANDROID_ARCHITECTURE = arm - -!equals(NDK_TOOLCHAIN_VERSION, 4.4.3): ANDROID_CXXSTL_SUFFIX = -$$NDK_TOOLCHAIN_VERSION - -NDK_TOOLCHAIN = $$NDK_TOOLCHAIN_PREFIX-$$NDK_TOOLCHAIN_VERSION -NDK_TOOLCHAIN_PATH = $$NDK_ROOT/toolchains/$$NDK_TOOLCHAIN/prebuilt/$$NDK_HOST - - -ANDROID_SDK_ROOT = $$(ANDROID_SDK_ROOT) -isEmpty(ANDROID_SDK_ROOT): ANDROID_SDK_ROOT = $$DEFAULT_ANDROID_SDK_ROOT - -ANDROID_SDK_BUILD_TOOLS_REVISION = $$(ANDROID_BUILD_TOOLS_REVISION) -isEmpty(ANDROID_SDK_BUILD_TOOLS_REVISION) { - SDK_BUILD_TOOLS_REVISIONS = $$files($$ANDROID_SDK_ROOT/build-tools/*) - for (REVISION, SDK_BUILD_TOOLS_REVISIONS) { - BASENAME = $$basename(REVISION) - greaterThan(BASENAME, $$ANDROID_SDK_BUILD_TOOLS_REVISION): ANDROID_SDK_BUILD_TOOLS_REVISION = $$BASENAME - } -} - -CONFIG += $$ANDROID_PLATFORM - -ANDROID_PLATFORM_ROOT_PATH = $$NDK_ROOT/platforms/$$ANDROID_PLATFORM/arch-$$ANDROID_ARCHITECTURE/ - -CROSS_COMPILE = $$NDK_TOOLCHAIN_PATH/bin/$$NDK_TOOLS_PREFIX- - -QMAKE_PCH_OUTPUT_EXT = .gch - -QMAKE_CFLAGS_PRECOMPILE = -x c-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} -QMAKE_CFLAGS_USE_PRECOMPILE = -include ${QMAKE_PCH_OUTPUT_BASE} -QMAKE_CXXFLAGS_PRECOMPILE = -x c++-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} -QMAKE_CXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE diff --git a/mkspecs/common/android-base-tail.conf b/mkspecs/common/android-base-tail.conf deleted file mode 100644 index c970379f28..0000000000 --- a/mkspecs/common/android-base-tail.conf +++ /dev/null @@ -1,82 +0,0 @@ -# In early configure setup; nothing useful to be done here. -isEmpty(DEFAULT_ANDROID_NDK_ROOT): return() - -# -fstack-protector-strong offers good protection against stack smashing attacks. -# It is (currently) enabled only on Android because we know for sure that Andoroid compilers supports it -QMAKE_CFLAGS += -fstack-protector-strong -DANDROID - -equals(ANDROID_TARGET_ARCH, armeabi-v7a): \ - QMAKE_CFLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=vfp -else: equals(ANDROID_TARGET_ARCH, armeabi): \ - QMAKE_CFLAGS += -march=armv5te -mtune=xscale -msoft-float - -QMAKE_CFLAGS_WARN_ON = -Wall -W -QMAKE_CFLAGS_WARN_OFF = -equals(ANDROID_TARGET_ARCH, armeabi-v7a) | equals(ANDROID_TARGET_ARCH, armeabi) { - CONFIG += optimize_size - QMAKE_CFLAGS_DEBUG = -g -marm -O0 - QMAKE_CFLAGS_RELEASE += -mthumb - QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -mthumb -} - -QMAKE_CFLAGS_SHLIB = -fPIC -QMAKE_CFLAGS_YACC = -Wno-unused -Wno-parentheses -QMAKE_CFLAGS_THREAD = -D_REENTRANT -QMAKE_CFLAGS_HIDESYMS = -fvisibility=hidden -QMAKE_CFLAGS_NEON = -mfpu=neon - -QMAKE_CFLAGS_GNUC99 = -std=gnu99 -QMAKE_CFLAGS_GNUC11 = -std=gnu11 -QMAKE_CXXFLAGS_CXX11 = -std=c++11 -QMAKE_CXXFLAGS_CXX14 = -std=c++14 -QMAKE_CXXFLAGS_CXX1Z = -std=c++1z -QMAKE_CXXFLAGS_GNUCXX11 = -std=gnu++11 -QMAKE_CXXFLAGS_GNUCXX14 = -std=gnu++14 -QMAKE_CXXFLAGS_GNUCXX1Z = -std=gnu++1z - -QMAKE_CXXFLAGS = $$QMAKE_CFLAGS -QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON -QMAKE_CXXFLAGS_WARN_OFF = $$QMAKE_CFLAGS_WARN_OFF -QMAKE_CXXFLAGS_RELEASE += $$QMAKE_CFLAGS_RELEASE -QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO += $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO -QMAKE_CXXFLAGS_DEBUG += $$QMAKE_CFLAGS_DEBUG -QMAKE_CXXFLAGS_SHLIB = $$QMAKE_CFLAGS_SHLIB -QMAKE_CXXFLAGS_YACC = $$QMAKE_CFLAGS_YACC -QMAKE_CXXFLAGS_THREAD = $$QMAKE_CFLAGS_THREAD -QMAKE_CXXFLAGS_HIDESYMS = $$QMAKE_CFLAGS_HIDESYMS -fvisibility-inlines-hidden - -# modifications to linux.conf -QMAKE_AR = $${CROSS_COMPILE}ar cqs -QMAKE_OBJCOPY = $${CROSS_COMPILE}objcopy -QMAKE_NM = $${CROSS_COMPILE}nm -P - -QMAKE_STRIP = -#$${CROSS_COMPILE}strip - -QMAKE_RANLIB = $${CROSS_COMPILE}ranlib - -QMAKE_INCDIR_POST = -QMAKE_INCDIR_X11 = -QMAKE_LIBDIR_X11 = -QMAKE_INCDIR_OPENGL = -QMAKE_LIBDIR_OPENGL = - -QMAKE_LINK_SHLIB = $$QMAKE_LINK -QMAKE_LFLAGS_APP = -Wl,--no-undefined -Wl,-z,noexecstack -shared -QMAKE_LFLAGS_SHLIB = -Wl,--no-undefined -Wl,-z,noexecstack -shared -QMAKE_LFLAGS_PLUGIN = $$QMAKE_LFLAGS_SHLIB -QMAKE_LFLAGS_NOUNDEF = -Wl,--no-undefined -QMAKE_LFLAGS_RPATH = -Wl,-rpath= -QMAKE_LFLAGS_RPATHLINK = -Wl,-rpath-link= - -QMAKE_LIBS_PRIVATE = $$ANDROID_CXX_STL_LIBS -llog -lz -lm -ldl -lc -QMAKE_LIBS_X11 = -QMAKE_LIBS_THREAD = -QMAKE_LIBS_EGL = -lEGL -QMAKE_LIBS_OPENGL = -QMAKE_LIBS_OPENGL_ES2 = -lGLESv2 - - -!exists($$NDK_ROOT): error("You need to set the ANDROID_NDK_ROOT environment variable to point to your Android NDK.") - -load(qt_config) diff --git a/mkspecs/features/android/android.prf b/mkspecs/features/android/android.prf index 0e6f4a4592..a12c17c4ed 100644 --- a/mkspecs/features/android/android.prf +++ b/mkspecs/features/android/android.prf @@ -16,17 +16,22 @@ APK_PATH = $$shell_path($$OUT_PWD/android-build/$${TARGET}.apk) } QMAKE_EXTRA_TARGETS *= apk apk_install_target -contains(TEMPLATE, ".*app") { - !android_app { - !contains(TARGET, ".so"): TARGET = lib$${TARGET}.so - QMAKE_LFLAGS += -Wl,-soname,$$shell_quote($$TARGET) +build_pass { + contains(TEMPLATE, ".*app") { + !android_app { + !contains(TARGET, ".so") { + single_arch:TARGET = lib$${TARGET}.so + else:TARGET = lib$${TARGET}_$${QT_ARCH}.so + } + QMAKE_LFLAGS += -Wl,-soname,$$shell_quote($$TARGET) - android_install { - target.path=/libs/$$ANDROID_TARGET_ARCH/ - INSTALLS *= target + android_install { + target.path=/libs/$$ANDROID_TARGET_ARCH/ + INSTALLS *= target + } } + } else: contains(TEMPLATE, "lib"):!static:!QTDIR_build:android_install { + target.path = /libs/$$ANDROID_TARGET_ARCH/ + INSTALLS *= target } -} else: contains(TEMPLATE, "lib"):!static:!QTDIR_build:android_install { - target.path = /libs/$$ANDROID_TARGET_ARCH/ - INSTALLS *= target } diff --git a/mkspecs/features/android/android_deployment_settings.prf b/mkspecs/features/android/android_deployment_settings.prf index 48943fa0f4..998a985bb5 100644 --- a/mkspecs/features/android/android_deployment_settings.prf +++ b/mkspecs/features/android/android_deployment_settings.prf @@ -17,32 +17,21 @@ contains(TEMPLATE, ".*app"):!build_pass:!android-embedded { isEmpty(NDK_ROOT): NDK_ROOT = $$DEFAULT_ANDROID_NDK_ROOT FILE_CONTENT += " \"ndk\": $$emitString($$NDK_ROOT)," - equals(ANDROID_USE_LLVM, true) { - FILE_CONTENT += " \"toolchain-prefix\": \"llvm\"," - FILE_CONTENT += " \"tool-prefix\": \"llvm\"," - } else { - NDK_TOOLCHAIN_PREFIX = $$(ANDROID_NDK_TOOLCHAIN_PREFIX) - isEmpty(NDK_TOOLCHAIN_PREFIX) { - equals(ANDROID_TARGET_ARCH, x86): NDK_TOOLCHAIN_PREFIX = x86 - else: equals(ANDROID_TARGET_ARCH, x86_64): NDK_TOOLCHAIN_PREFIX = x86_64 - else: equals(ANDROID_TARGET_ARCH, arm64-v8a): NDK_TOOLCHAIN_PREFIX = aarch64-linux-android - else: NDK_TOOLCHAIN_PREFIX = arm-linux-androideabi - } - FILE_CONTENT += " \"toolchain-prefix\": $$emitString($$NDK_TOOLCHAIN_PREFIX)," - FILE_CONTENT += " \"tool-prefix\": $$emitString($$NDK_TOOLS_PREFIX)," - } - - NDK_TOOLCHAIN_VERSION = $$(ANDROID_NDK_TOOLCHAIN_VERSION) - isEmpty(NDK_TOOLCHAIN_VERSION): NDK_TOOLCHAIN_VERSION = $$DEFAULT_ANDROID_NDK_TOOLCHAIN_VERSION - FILE_CONTENT += " \"toolchain-version\": $$emitString($$NDK_TOOLCHAIN_VERSION)," + FILE_CONTENT += " \"toolchain-prefix\": \"llvm\"," + FILE_CONTENT += " \"tool-prefix\": \"llvm\"," NDK_HOST = $$(ANDROID_NDK_HOST) isEmpty(NDK_HOST): NDK_HOST = $$DEFAULT_ANDROID_NDK_HOST FILE_CONTENT += " \"ndk-host\": $$emitString($$NDK_HOST)," - ANDROID_TARGET_ARCH = $$(ANDROID_TARGET_ARCH) - isEmpty(ANDROID_TARGET_ARCH): ANDROID_TARGET_ARCH = $$DEFAULT_ANDROID_TARGET_ARCH - FILE_CONTENT += " \"target-architecture\": $$emitString($$ANDROID_TARGET_ARCH)," + for (arch, ANDROID_ABIS) { + equals(arch, x86): libs_arch = i686-linux-android + else: equals(arch, x86_64): libs_arch = x86_64-linux-android + else: equals(arch, arm64-v8a): libs_arch = aarch64-linux-android + else: libs_arch = arm-linux-androideabi + ARCHS += "$$emitString($$arch):$$emitString($$libs_arch)" + } + FILE_CONTENT += " \"architectures\": {$$join(ARCHS,", ")}," # Explicitly set qt dependencies of application for deployment !isEmpty(ANDROID_DEPLOYMENT_DEPENDENCIES): \ @@ -74,9 +63,8 @@ contains(TEMPLATE, ".*app"):!build_pass:!android-embedded { QML_ROOT_PATH = $$_PRO_FILE_PWD_ FILE_CONTENT += " \"qml-root-path\": $$emitString($$QML_ROOT_PATH)," FILE_CONTENT += " \"stdcpp-path\": $$emitString($$ANDROID_STDCPP_PATH)," - FILE_CONTENT += " \"useLLVM\": $$ANDROID_USE_LLVM," - - FILE_CONTENT += " \"application-binary\": $$emitString($$absolute_path($$DESTDIR, $$OUT_PWD)/$$TARGET)" + FILE_CONTENT += "" + FILE_CONTENT += " \"application-binary\": $$emitString($$TARGET)" FILE_CONTENT += "}" isEmpty(ANDROID_DEPLOYMENT_SETTINGS_FILE): ANDROID_DEPLOYMENT_SETTINGS_FILE = $$OUT_PWD/android-$$TARGET-deployment-settings.json diff --git a/mkspecs/features/android/default_pre.prf b/mkspecs/features/android/default_pre.prf new file mode 100644 index 0000000000..d4f84a8fcc --- /dev/null +++ b/mkspecs/features/android/default_pre.prf @@ -0,0 +1,76 @@ +load(default_pre) + +build_pass:armeabi-v7a { + QT_ARCH = armeabi-v7a +} else:build_pass:arm64-v8a { + QT_ARCH = arm64-v8a +} else:build_pass:x86 { + QT_ARCH = x86 +} else:build_pass:x86_64 { + QT_ARCH = x86_64 +} else { + # default architecture + QT_ARCH = arm64-v8a +} + +DEFAULT_ANDROID_TARGET_ARCH=$${QT_ARCH} + +ANDROID_TARGET_ARCH = $$(ANDROID_TARGET_ARCH) +isEmpty(ANDROID_TARGET_ARCH): ANDROID_TARGET_ARCH = $$DEFAULT_ANDROID_TARGET_ARCH + +# Follow https://android.googlesource.com/platform/ndk/+/ndk-release-r20/docs/BuildSystemMaintainers.md + +equals(ANDROID_TARGET_ARCH, armeabi-v7a): \ + QMAKE_CFLAGS = -target armv7a-linux-androideabi$$replace(ANDROID_PLATFORM, "android-", "") +else: equals(ANDROID_TARGET_ARCH, arm64-v8a): \ + QMAKE_CFLAGS = -target aarch64-linux-android$$replace(ANDROID_PLATFORM, "android-", "") +else: equals(ANDROID_TARGET_ARCH, x86): \ + QMAKE_CFLAGS = -target i686-linux-android$$replace(ANDROID_PLATFORM, "android-", "") -mstackrealign +else: equals(ANDROID_TARGET_ARCH, x86_64): \ + QMAKE_CFLAGS = -target x86_64-linux-android$$replace(ANDROID_PLATFORM, "android-", "") + +QMAKE_CFLAGS += -fno-limit-debug-info + +QMAKE_LINK = $$QMAKE_CXX $$QMAKE_CFLAGS + +ANDROID_STDCPP_PATH = $$NDK_LLVM_PATH/sysroot/usr/lib/ + +# -fstack-protector-strong offers good protection against stack smashing attacks. +# It is (currently) enabled only on Android because we know for sure that Android compilers supports it +QMAKE_CFLAGS += -fPIC -fstack-protector-strong -DANDROID + + +equals(ANDROID_TARGET_ARCH, armeabi-v7a) | equals(ANDROID_TARGET_ARCH, armeabi) { + CONFIG += optimize_size + QMAKE_CFLAGS_DEBUG = -g -marm -O0 + QMAKE_CFLAGS_RELEASE += -mthumb + QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -mthumb +} + +QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO = $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO + +QMAKE_CXXFLAGS = $$QMAKE_CFLAGS +QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON +QMAKE_CXXFLAGS_WARN_OFF = $$QMAKE_CFLAGS_WARN_OFF +QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE +QMAKE_CXXFLAGS_DEBUG = $$QMAKE_CFLAGS_DEBUG +QMAKE_CXXFLAGS_SHLIB = $$QMAKE_CFLAGS_SHLIB +QMAKE_CXXFLAGS_YACC = $$QMAKE_CFLAGS_YACC +QMAKE_CXXFLAGS_THREAD = $$QMAKE_CFLAGS_THREAD + +QMAKE_LIBS_EGL = -lEGL +QMAKE_LIBS_OPENGL_ES2 = -lGLESv2 + +# modifications to linux.conf +QMAKE_AR = $${CROSS_COMPILE}ar cqs +QMAKE_OBJCOPY = $${CROSS_COMPILE}objcopy +QMAKE_NM = $${CROSS_COMPILE}nm -P + +QMAKE_STRIP = +#$${CROSS_COMPILE}strip + +QMAKE_RANLIB = $${CROSS_COMPILE}ranlib +QMAKE_LINK_SHLIB = $$QMAKE_LINK +QMAKE_LFLAGS = + +QMAKE_LIBS_PRIVATE = -llog -lz -lm -ldl -lc diff --git a/mkspecs/features/android/resolve_config.prf b/mkspecs/features/android/resolve_config.prf new file mode 100644 index 0000000000..c542017e31 --- /dev/null +++ b/mkspecs/features/android/resolve_config.prf @@ -0,0 +1,10 @@ +load(resolve_config) + +!host_build:!single_arch:!java:android { + isEmpty(ANDROID_ABIS): ANDROID_ABIS = $$ALL_ANDROID_ABIS + + ALL_ABIS = $$join(ANDROID_ABIS, _and_) + CONFIG += $$ALL_ABIS build_all + addExclusiveBuildsProper($$ALL_ABIS, $$ANDROID_ABIS) + unset(ALL_ABIS) +} diff --git a/mkspecs/features/exclusive_builds_post.prf b/mkspecs/features/exclusive_builds_post.prf index 936085af0b..a9c341a2d7 100644 --- a/mkspecs/features/exclusive_builds_post.prf +++ b/mkspecs/features/exclusive_builds_post.prf @@ -1,4 +1,6 @@ +load(qt_functions) + contains(TEMPLATE, subdirs) { for(build, QMAKE_EXCLUSIVE_BUILDS) { prepareRecursiveTarget($$build) diff --git a/mkspecs/features/qmake_use.prf b/mkspecs/features/qmake_use.prf index 64faa4f215..ecb4f7ed41 100644 --- a/mkspecs/features/qmake_use.prf +++ b/mkspecs/features/qmake_use.prf @@ -22,7 +22,11 @@ for(ever) { !defined(QMAKE_LIBS_$$nu, var): \ error("Library '$$lower($$replace(nu, _, -))' is not defined.") - debug: \ + android { + ABI_LIBS = $$eval(QMAKE_LIBS_$${nu}_$${QT_ARCH}) + isEmpty(ABI_LIBS): ABI_LIBS = $$eval(QMAKE_LIBS_$${nu}) + LIBS$${suffix} += $$ABI_LIBS + } else: debug: \ LIBS$${suffix} += $$eval(QMAKE_LIBS_$${nu}_DEBUG) $$eval(QMAKE_LIBS_$$nu) else: \ LIBS$${suffix} += $$eval(QMAKE_LIBS_$${nu}_RELEASE) $$eval(QMAKE_LIBS_$$nu) diff --git a/mkspecs/features/qt_android_deps.prf b/mkspecs/features/qt_android_deps.prf index c172ca8c4e..e50c24b966 100644 --- a/mkspecs/features/qt_android_deps.prf +++ b/mkspecs/features/qt_android_deps.prf @@ -16,7 +16,7 @@ ANDROID_DEPENDS_DIR = $$MODULE_BASE_OUTDIR/lib/ DEPENDENCY_FILE = $$ANDROID_DEPENDS_DIR$$TARGET-android-dependencies.xml -!build_pass { +build_pass:!isEmpty(QT_ARCH): { !isEmpty(MODULE_PLUGIN_TYPES) { for(PLUGIN_TYPE, MODULE_PLUGIN_TYPES) { ANDROID_BUNDLED_FILES += "plugins/$$PLUGIN_TYPE" @@ -46,6 +46,8 @@ DEPENDENCY_FILE = $$ANDROID_DEPENDS_DIR$$TARGET-android-dependencies.xml EXTENDS = $$section(LIB_FILE, ":", 1, 1) !isEmpty(EXTENDS): EXTENDS = "extends=\"$$EXTENDS\"" LIB_FILE = $$section(LIB_FILE, ":", 0, 0) + LIB_FILE = $$replace(LIB_FILE,".so", "_$${QT_ARCH}.so") + !isEmpty(EXTENDS): EXTENDS = $$replace(EXTENDS,".so", "_$${QT_ARCH}.so") FILE_CONTENT += "" } } @@ -54,12 +56,14 @@ DEPENDENCY_FILE = $$ANDROID_DEPENDS_DIR$$TARGET-android-dependencies.xml for(REPLACEMENT, ANDROID_LIB_DEPENDENCY_REPLACEMENTS) { REPLACEMENT_FILE = $$section(REPLACEMENT, ":", 0, 0) LIB_FILE = $$section(REPLACEMENT, ":", 1, 1) + REPLACEMENT_FILE = $$replace(REPLACEMENT_FILE,".so", "_$${QT_ARCH}.so") FILE_CONTENT += "" } } !isEmpty(ANDROID_BUNDLED_FILES) { for (BUNDLED_FILE, ANDROID_BUNDLED_FILES) { + BUNDLED_FILE = $$replace(BUNDLED_FILE,".so", "_$${QT_ARCH}.so") FILE_CONTENT += "" } } diff --git a/mkspecs/features/qt_configure.prf b/mkspecs/features/qt_configure.prf index 2b86caebd0..1219fe1443 100644 --- a/mkspecs/features/qt_configure.prf +++ b/mkspecs/features/qt_configure.prf @@ -560,7 +560,7 @@ defineTest(qtConfResolveLibs) { } else { paths += $$lp } - } else: contains(l, "^-l.*") { + } else: !android: contains(l, "^-l.*") { lib = $$replace(l, "^-l", ) lcan = integrity:contains(lib, "^.*\\.a") { diff --git a/mkspecs/features/qt_functions.prf b/mkspecs/features/qt_functions.prf index 1903e509c8..ede494eec1 100644 --- a/mkspecs/features/qt_functions.prf +++ b/mkspecs/features/qt_functions.prf @@ -1,7 +1,8 @@ defineReplace(qtPlatformTargetSuffix) { suffix = - CONFIG(debug, debug|release) { + android: return($${suffix}_$${QT_ARCH}) + else: CONFIG(debug, debug|release) { !debug_and_release|build_pass { mac: return($${suffix}_debug) win32: return($${suffix}d) diff --git a/mkspecs/features/qt_helper_lib.prf b/mkspecs/features/qt_helper_lib.prf index 2cb54fc547..216c24c7aa 100644 --- a/mkspecs/features/qt_helper_lib.prf +++ b/mkspecs/features/qt_helper_lib.prf @@ -29,19 +29,19 @@ DLLDESTDIR = $$MODULE_BASE_OUTDIR/bin THE_TARGET = $$qt5LibraryTarget($$TARGET) -!build_pass { - MODULE = $$replace(TARGET, ^qt, ) - MODULE ~= s,-,_, - MODULE_PRI = $$MODULE_QMAKE_OUTDIR/mkspecs/modules/qt_ext_$${MODULE}.pri - ucmodule = $$upper($$MODULE) +MODULE = $$replace(TARGET, ^qt, ) +MODULE ~= s,-,_, +MODULE_PRI = $$MODULE_QMAKE_OUTDIR/mkspecs/modules/qt_ext_$${MODULE}.pri +ucmodule = $$upper($$MODULE) +win32|CONFIG(static, static|shared) { + prefix = $$QMAKE_PREFIX_STATICLIB + suffix = $$QMAKE_EXTENSION_STATICLIB +} else { + prefix = $$QMAKE_PREFIX_SHLIB + suffix = $$QMAKE_EXTENSION_SHLIB +} - win32|CONFIG(static, static|shared) { - prefix = $$QMAKE_PREFIX_STATICLIB - suffix = $$QMAKE_EXTENSION_STATICLIB - } else { - prefix = $$QMAKE_PREFIX_SHLIB - suffix = $$QMAKE_EXTENSION_SHLIB - } +!build_pass { CC_USES = LD_USES = for (use, QMAKE_USE) { @@ -58,7 +58,9 @@ THE_TARGET = $$qt5LibraryTarget($$TARGET) "QMAKE_DEPENDS_$${ucmodule}_LD =$$join(LD_USES, " ", " ")" \ "QMAKE_INCDIR_$${ucmodule} = $$val_escape(MODULE_INCLUDEPATH)" \ "QMAKE_DEFINES_$${ucmodule} = $$val_escape(MODULE_DEFINES)" - debug_and_release { + android { + MODULE_PRI_CONT += "QMAKE_LIBS_$${ucmodule} =" + } else: debug_and_release { win32: \ MODULE_DEBUG_LIBS = $$DESTDIR/$$prefix$${TARGET}d.$$suffix else: darwin: \ @@ -76,6 +78,11 @@ THE_TARGET = $$qt5LibraryTarget($$TARGET) "QMAKE_LIBS_$${ucmodule} = $$val_escape(MODULE_LIBS)" } write_file($$MODULE_PRI, MODULE_PRI_CONT)|error() +} else: android { + ABI_TARGET = $$qt5LibraryTarget($$TARGET) + ABI_MODULE_LIBS = $$DESTDIR/$$prefix$${ABI_TARGET}.$$suffix + MODULE_PRI_CONT = "QMAKE_LIBS_$${ucmodule}_$${QT_ARCH} = $$val_escape(ABI_MODULE_LIBS)" + write_file($$MODULE_PRI, MODULE_PRI_CONT, append)|error() } TARGET = $$THE_TARGET diff --git a/mkspecs/features/qt_module_pris.prf b/mkspecs/features/qt_module_pris.prf index e892f83432..719caf3d4a 100644 --- a/mkspecs/features/qt_module_pris.prf +++ b/mkspecs/features/qt_module_pris.prf @@ -51,13 +51,12 @@ defineReplace(qtGetExportsForModule) { return($$result) } -defineReplace(qtExportLibsForModule) { +defineReplace(qtExportDepsForModule) { result = for (lib, QT.$${1}.libraries) { NAME = $$upper($$lib) vars = \ QMAKE_DEPENDS_$${NAME}_CC QMAKE_DEPENDS_$${NAME}_LD \ - QMAKE_LIBS_$$NAME QMAKE_LIBS_$${NAME}_DEBUG QMAKE_LIBS_$${NAME}_RELEASE \ QMAKE_DEFINES_$$NAME QMAKE_INCDIR_$$NAME for (var, vars) { expvar = $$var @@ -71,6 +70,24 @@ defineReplace(qtExportLibsForModule) { return($$result) } +defineReplace(qtExportLibsForModule) { + result = + for (lib, QT.$${1}.libraries) { + NAME = $$upper($$lib) + vars = \ + QMAKE_LIBS_$$NAME QMAKE_LIBS_$${NAME}_DEBUG QMAKE_LIBS_$${NAME}_RELEASE + for (var, vars) { + expvar = $$var + expvar ~= s/^QMAKE_/QMAKE_EXPORT_/ + defined($$expvar, var):equals($$expvar, -): next() + !defined($$expvar, var): expvar = $$var + defined($$expvar, var): \ + result += "$$var$${2} = $$val_escape($$expvar)" + } + } + return($$result) +} + !build_pass { # Create a module .pri file @@ -160,6 +177,7 @@ defineReplace(qtExportLibsForModule) { "QT.$${MODULE}_private.module_config =$$join(module_build_type, " ", " ")" \ $$qtGetFeaturesForModule($${MODULE}_private) \ "" \ + $$qtExportDepsForModule($${MODULE}_private) \ $$qtExportLibsForModule($${MODULE}_private) write_file($$MODULE_PRIVATE_PRI, MODULE_PRIVATE_PRI_CONT)|error() } @@ -220,7 +238,10 @@ defineReplace(qtExportLibsForModule) { } cache(QT_MODULES, transient) -} # !build_pass +} else:android:!no_private_module:!internal_module { + MODULE_PRIVATE_PRI_CONT = $$qtExportLibsForModule($${MODULE}_private, _$${QT_ARCH}) + write_file($$MODULE_PRIVATE_PRI, MODULE_PRIVATE_PRI_CONT, append)|error() +} # Schedule the regular .pri file for installation CONFIG += qt_install_module diff --git a/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties b/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties index bf3de21830..4b7e1f3d38 100644 --- a/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties +++ b/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/android/jar/jar.pro b/src/android/jar/jar.pro index ac6fc79968..24a83d56a1 100644 --- a/src/android/jar/jar.pro +++ b/src/android/jar/jar.pro @@ -1,6 +1,7 @@ TARGET = QtAndroid CONFIG += java + DESTDIR = $$[QT_INSTALL_PREFIX/get]/jar PATHPREFIX = $$PWD/src/org/qtproject/qt5/android/ diff --git a/src/android/java/java.pro b/src/android/java/java.pro index 9d37eb1026..7f0dfa8a1b 100644 --- a/src/android/java/java.pro +++ b/src/android/java/java.pro @@ -1,3 +1,5 @@ +CONFIG += single_arch + CONFIG -= qt android_install javaresources.files = \ diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java index d3b0600b2f..45941e8ed8 100644 --- a/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java +++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java @@ -1,5 +1,5 @@ /* - Copyright (c) 2016, BogDan Vatra + Copyright (c) 2019, BogDan Vatra Contact: http://www.qt.io/licensing/ Commercial License Usage @@ -63,9 +63,12 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.reflect.Array; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; +import java.util.List; import dalvik.system.DexClassLoader; @@ -85,7 +88,6 @@ public abstract class QtLoader { public static final String ENVIRONMENT_VARIABLES_KEY = "environment.variables"; public static final String APPLICATION_PARAMETERS_KEY = "application.parameters"; public static final String BUNDLED_LIBRARIES_KEY = "bundled.libraries"; - public static final String QT_LIBS_RESOURCE_ID_KEY = "android.app.qt_libs_resource_id"; public static final String BUNDLED_IN_LIB_RESOURCE_ID_KEY = "android.app.bundled_in_lib_resource_id"; public static final String BUNDLED_IN_ASSETS_RESOURCE_ID_KEY = "android.app.bundled_in_assets_resource_id"; public static final String MAIN_LIBRARY_KEY = "main.library"; @@ -153,7 +155,7 @@ public abstract class QtLoader { // this repository is used to push a new release, and should be used to test your application. // * unstable - unstable repository, DO NOT use this repository in production, // this repository is used to push Qt snapshots. - public String[] m_qtLibs = null; // required qt libs + public ArrayList m_qtLibs = null; // required qt libs public int m_displayDensity = -1; private ContextWrapper m_context; protected ComponentInfo m_contextInfo; @@ -191,6 +193,36 @@ public abstract class QtLoader { } // Implement in subclass + private final List supportedAbis = Arrays.asList(Build.SUPPORTED_ABIS); + private String preferredAbi = null; + + private ArrayList prefferedAbiLibs(String []libs) + { + HashMap> abisLibs = new HashMap<>(); + for (String lib : libs) { + String[] archLib = lib.split(";", 2); + if (preferredAbi != null && !archLib[0].equals(preferredAbi)) + continue; + if (!abisLibs.containsKey(archLib[0])) + abisLibs.put(archLib[0], new ArrayList()); + abisLibs.get(archLib[0]).add(archLib[1]); + } + + if (preferredAbi != null) { + if (abisLibs.containsKey(preferredAbi)) { + return abisLibs.get(preferredAbi); + } + return new ArrayList(); + } + + for (String abi: supportedAbis) { + if (abisLibs.containsKey(abi)) { + preferredAbi = abi; + return abisLibs.get(abi); + } + } + return new ArrayList(); + } // this function is used to load and start the loader private void loadApplication(Bundle loaderParams) @@ -218,12 +250,14 @@ public abstract class QtLoader { // add all bundled Qt libs to loader params ArrayList libs = new ArrayList(); - if (m_contextInfo.metaData.containsKey("android.app.bundled_libs_resource_id")) - libs.addAll(Arrays.asList(m_context.getResources().getStringArray(m_contextInfo.metaData.getInt("android.app.bundled_libs_resource_id")))); + if (m_contextInfo.metaData.containsKey("android.app.bundled_libs_resource_id")) { + int resourceId = m_contextInfo.metaData.getInt("android.app.bundled_libs_resource_id"); + libs.addAll(prefferedAbiLibs(m_context.getResources().getStringArray(resourceId))); + } String libName = null; if (m_contextInfo.metaData.containsKey("android.app.lib_name")) { - libName = m_contextInfo.metaData.getString("android.app.lib_name"); + libName = m_contextInfo.metaData.getString("android.app.lib_name") + "_" + preferredAbi; loaderParams.putString(MAIN_LIBRARY_KEY, libName); //main library contains main() function } @@ -278,7 +312,7 @@ public abstract class QtLoader { try { if (m_service != null) { Bundle parameters = new Bundle(); - parameters.putStringArray(REQUIRED_MODULES_KEY, m_qtLibs); + parameters.putStringArray(REQUIRED_MODULES_KEY, (String[]) m_qtLibs.toArray()); parameters.putString(APPLICATION_TITLE_KEY, getTitle()); parameters.putInt(MINIMUM_MINISTRO_API_KEY, MINISTRO_API_LEVEL); parameters.putInt(MINIMUM_QT_VERSION_KEY, QT_VERSION); @@ -464,7 +498,8 @@ public abstract class QtLoader { // why can't we load the plugins directly from libs ?!?! String key = BUNDLED_IN_LIB_RESOURCE_ID_KEY; if (m_contextInfo.metaData.containsKey(key)) { - String[] list = m_context.getResources().getStringArray(m_contextInfo.metaData.getInt(key)); + int resourceId = m_contextInfo.metaData.getInt(key); + ArrayList list = prefferedAbiLibs(m_context.getResources().getStringArray(resourceId)); for (String bundledImportBinary : list) { String[] split = bundledImportBinary.split(":"); @@ -603,7 +638,7 @@ public abstract class QtLoader { if (m_contextInfo.metaData.containsKey("android.app.qt_libs_resource_id")) { int resourceId = m_contextInfo.metaData.getInt("android.app.qt_libs_resource_id"); - m_qtLibs = m_context.getResources().getStringArray(resourceId); + m_qtLibs = prefferedAbiLibs(m_context.getResources().getStringArray(resourceId)); } if (m_contextInfo.metaData.containsKey("android.app.use_local_qt_libs") @@ -617,6 +652,7 @@ public abstract class QtLoader { apkDeployFromSystem = true; String libsDir = null; + String bundledLibsDir = null; if (apkDeployFromSystem) { String systemLibsPrefix = SYSTEM_LIB_PATH; if (m_contextInfo.metaData.containsKey("android.app.system_libs_prefix")) { @@ -633,8 +669,11 @@ public abstract class QtLoader { } else { String nativeLibraryPrefix = m_context.getApplicationInfo().nativeLibraryDir + "/"; File nativeLibraryDir = new File(nativeLibraryPrefix); - if (nativeLibraryDir.exists() && nativeLibraryDir.isDirectory() && nativeLibraryDir.list().length > 0) + if (nativeLibraryDir.exists() && nativeLibraryDir.isDirectory() && nativeLibraryDir.list().length > 0) { libsDir = nativeLibraryPrefix; + bundledLibsDir = nativeLibraryPrefix; + } + } if (apkDeployFromSystem && libsDir == null) @@ -643,8 +682,8 @@ public abstract class QtLoader { if (m_qtLibs != null) { String libPrefix = libsDir + "lib"; - for (int i = 0; i < m_qtLibs.length; i++) - libraryList.add(libPrefix + m_qtLibs[i] + ".so"); + for (String lib : m_qtLibs) + libraryList.add(libPrefix + lib + ".so"); } if (m_contextInfo.metaData.containsKey("android.app.bundle_local_qt_libs") @@ -654,22 +693,26 @@ public abstract class QtLoader { String pluginsPrefix = dataPath + "qt-reserved-files/"; if (libsDir == null) - throw new Exception(""); + throw new Exception("Invalid libsDir"); cleanOldCacheIfNecessary(dataPath, pluginsPrefix); extractBundledPluginsAndImports(pluginsPrefix, libsDir); if (m_contextInfo.metaData.containsKey(BUNDLED_IN_LIB_RESOURCE_ID_KEY)) { - String[] extraLibs = m_contextInfo.metaData.getString("android.app.load_local_libs").split(":"); - for (String lib : extraLibs) { - if (!lib.isEmpty()) - libraryList.add(pluginsPrefix + lib); + int resourceId = m_contextInfo.metaData.getInt("android.app.load_local_libs_resource_id"); + for (String libs : prefferedAbiLibs(m_context.getResources().getStringArray(resourceId))) { + for (String lib : libs.split(":")) { + if (!lib.isEmpty()) + libraryList.add(libsDir + lib); + } } } ENVIRONMENT_VARIABLES += "\tQML2_IMPORT_PATH=" + pluginsPrefix + "/qml" + "\tQML_IMPORT_PATH=" + pluginsPrefix + "/imports" + "\tQT_PLUGIN_PATH=" + pluginsPrefix + "/plugins"; + if (bundledLibsDir != null) + ENVIRONMENT_VARIABLES += "\tQT_BUNDLED_LIBS_PATH=" + bundledLibsDir; } Bundle loaderParams = new Bundle(); diff --git a/src/android/templates/AndroidManifest.xml b/src/android/templates/AndroidManifest.xml index aed8a3c888..75da314c2b 100644 --- a/src/android/templates/AndroidManifest.xml +++ b/src/android/templates/AndroidManifest.xml @@ -12,7 +12,7 @@ - + + - + diff --git a/src/android/templates/build.gradle b/src/android/templates/build.gradle index 8d4aa63153..d2da115936 100644 --- a/src/android/templates/build.gradle +++ b/src/android/templates/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.2.0' + classpath 'com.android.tools.build:gradle:3.5.0' } } diff --git a/src/android/templates/res/values/libs.xml b/src/android/templates/res/values/libs.xml index 4009a7785a..db777bf433 100644 --- a/src/android/templates/res/values/libs.xml +++ b/src/android/templates/res/values/libs.xml @@ -1,7 +1,7 @@ - https://download.qt.io/ministro/android/qt5/qt-5.9 + https://download.qt.io/ministro/android/qt5/qt-5.14 + + + + + + diff --git a/src/android/templates/templates.pro b/src/android/templates/templates.pro index 55387f3af7..9a64251ee3 100644 --- a/src/android/templates/templates.pro +++ b/src/android/templates/templates.pro @@ -1,3 +1,5 @@ +CONFIG += single_arch + CONFIG -= qt android_install templates.files = \ diff --git a/src/corelib/corelib.pro b/src/corelib/corelib.pro index b9bcc70e17..121db51eb5 100644 --- a/src/corelib/corelib.pro +++ b/src/corelib/corelib.pro @@ -12,6 +12,7 @@ CONFIG += qt_tracepoints CONFIG += $$MODULE_CONFIG DEFINES += $$MODULE_DEFINES +android: DEFINES += LIBS_SUFFIX='\\"_$${QT_ARCH}.so\\"' DEFINES += QT_NO_USING_NAMESPACE QT_NO_FOREACH msvc:equals(QT_ARCH, i386): QMAKE_LFLAGS += /BASE:0x67000000 diff --git a/src/corelib/plugin/qlibrary_unix.cpp b/src/corelib/plugin/qlibrary_unix.cpp index 85ada9197c..44d5513163 100644 --- a/src/corelib/plugin/qlibrary_unix.cpp +++ b/src/corelib/plugin/qlibrary_unix.cpp @@ -100,6 +100,9 @@ QStringList QLibraryPrivate::suffixes_sys(const QString& fullVersion) suffixes << QLatin1String(".so.%1").arg(fullVersion); } else { suffixes << QLatin1String(".so"); +# ifdef Q_OS_ANDROID + suffixes << QStringLiteral(LIBS_SUFFIX); +# endif } #endif # ifdef Q_OS_MAC @@ -226,7 +229,14 @@ bool QLibraryPrivate::load_sys() } else { attempt = path + prefixes.at(prefix) + name + suffixes.at(suffix); } + pHnd = dlopen(QFile::encodeName(attempt), dlFlags); +#ifdef Q_OS_ANDROID + if (!pHnd) { + auto attemptFromBundle = attempt; + pHnd = dlopen(QFile::encodeName(attemptFromBundle.replace(QLatin1Char('/'), QLatin1Char('_'))), dlFlags); + } +#endif if (!pHnd && fileName.startsWith(QLatin1Char('/')) && QFile::exists(attempt)) { // We only want to continue if dlopen failed due to that the shared library did not exist. diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri index 70fccbc378..3b2ced3f58 100644 --- a/src/gui/image/image.pri +++ b/src/gui/image/image.pri @@ -82,7 +82,18 @@ qtConfig(png) { } # SIMD -SSSE3_SOURCES += image/qimage_ssse3.cpp -NEON_SOURCES += image/qimage_neon.cpp -MIPS_DSPR2_SOURCES += image/qimage_mips_dspr2.cpp -MIPS_DSPR2_ASM += image/qimage_mips_dspr2_asm.S +!android { + SSSE3_SOURCES += image/qimage_ssse3.cpp + NEON_SOURCES += image/qimage_neon.cpp + MIPS_DSPR2_SOURCES += image/qimage_mips_dspr2.cpp + MIPS_DSPR2_ASM += image/qimage_mips_dspr2_asm.S +} else { + # see https://developer.android.com/ndk/guides/abis + arm64-v8a { + SOURCES += image/qimage_neon.cpp + } + x86 | x86_64 { + DEFINES += QT_COMPILER_SUPPORTS_SSE2 QT_COMPILER_SUPPORTS_SSE3 QT_COMPILER_SUPPORTS_SSSE3 + SOURCES += image/qimage_ssse3.cpp + } +} diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index 972cf387ff..fcf6488edd 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -135,23 +135,41 @@ gcc:equals(QT_GCC_MAJOR_VERSION, 5) { NO_PCH_SOURCES += painting/qdrawhelper.cpp } -SSE2_SOURCES += painting/qdrawhelper_sse2.cpp -SSSE3_SOURCES += painting/qdrawhelper_ssse3.cpp -SSE4_1_SOURCES += painting/qdrawhelper_sse4.cpp \ - painting/qimagescale_sse4.cpp -ARCH_HASWELL_SOURCES += painting/qdrawhelper_avx2.cpp +!android { + SSE2_SOURCES += painting/qdrawhelper_sse2.cpp + SSSE3_SOURCES += painting/qdrawhelper_ssse3.cpp + SSE4_1_SOURCES += painting/qdrawhelper_sse4.cpp \ + painting/qimagescale_sse4.cpp + ARCH_HASWELL_SOURCES += painting/qdrawhelper_avx2.cpp -NEON_SOURCES += painting/qdrawhelper_neon.cpp painting/qimagescale_neon.cpp -NEON_HEADERS += painting/qdrawhelper_neon_p.h + NEON_SOURCES += painting/qdrawhelper_neon.cpp painting/qimagescale_neon.cpp + NEON_HEADERS += painting/qdrawhelper_neon_p.h +} !uikit:!win32:contains(QT_ARCH, "arm"): CONFIG += no_clang_integrated_as -!uikit:!win32:!integrity:!contains(QT_ARCH, "arm64") { +!android:!uikit:!win32:!integrity:!contains(QT_ARCH, "arm64") { NEON_ASM += ../3rdparty/pixman/pixman-arm-neon-asm.S painting/qdrawhelper_neon_asm.S DEFINES += ENABLE_PIXMAN_DRAWHELPERS } -MIPS_DSP_SOURCES += painting/qdrawhelper_mips_dsp.cpp -MIPS_DSP_HEADERS += painting/qdrawhelper_mips_dsp_p.h painting/qt_mips_asm_dsp_p.h -MIPS_DSP_ASM += painting/qdrawhelper_mips_dsp_asm.S -MIPS_DSPR2_ASM += painting/qdrawhelper_mips_dspr2_asm.S +!android { + MIPS_DSP_SOURCES += painting/qdrawhelper_mips_dsp.cpp + MIPS_DSP_HEADERS += painting/qdrawhelper_mips_dsp_p.h painting/qt_mips_asm_dsp_p.h + MIPS_DSP_ASM += painting/qdrawhelper_mips_dsp_asm.S + MIPS_DSPR2_ASM += painting/qdrawhelper_mips_dspr2_asm.S +} else { + # see https://developer.android.com/ndk/guides/abis + x86 | x86_64 { + DEFINES += QT_COMPILER_SUPPORTS_SSE2 QT_COMPILER_SUPPORTS_SSE3 QT_COMPILER_SUPPORTS_SSSE3 + SOURCES += painting/qdrawhelper_sse2.cpp painting/qdrawhelper_ssse3.cpp + } + x86_64 { + DEFINES += QT_COMPILER_SUPPORTS_SSE4_1 QT_COMPILER_SUPPORTS_SSE4_2 + SOURCES += painting/qdrawhelper_sse4.cpp painting/qimagescale_sse4.cpp + } + arm64-v8a { + SOURCES += painting/qdrawhelper_neon.cpp painting/qimagescale_neon.cpp + HEADERS += painting/qdrawhelper_neon_p.h + } +} include($$PWD/../../3rdparty/zlib_dependency.pri) diff --git a/src/plugins/bearer/android/jar/jar.pro b/src/plugins/bearer/android/jar/jar.pro index f988019dac..8277a8abc1 100644 --- a/src/plugins/bearer/android/jar/jar.pro +++ b/src/plugins/bearer/android/jar/jar.pro @@ -1,3 +1,5 @@ +CONFIG += single_arch + TARGET = QtAndroidBearer load(qt_build_paths) diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp index 10bbd59bfb..4c7b8a6917 100644 --- a/src/tools/androiddeployqt/main.cpp +++ b/src/tools/androiddeployqt/main.cpp @@ -91,7 +91,7 @@ FILE *openProcess(const QString &command) #if defined(Q_OS_WIN32) QString processedCommand = QLatin1Char('\"') + command + QLatin1Char('\"'); #else - QString processedCommand = command; + const QString& processedCommand = command; #endif return popen(processedCommand.toLocal8Bit().constData(), QT_POPEN_READ); @@ -99,7 +99,7 @@ FILE *openProcess(const QString &command) struct QtDependency { - QtDependency(QString rpath, QString apath) : relativePath(rpath), absolutePath(apath) {} + QtDependency(const QString &rpath, const QString &apath) : relativePath(rpath), absolutePath(apath) {} bool operator==(const QtDependency &other) const { @@ -127,7 +127,6 @@ struct Options , sectionsOnly(false) , protectedAuthenticationPath(false) , jarSigner(false) - , gdbServer(Auto) , installApk(false) , uninstallApk(false) {} @@ -150,7 +149,6 @@ struct Options bool generateAssetsFileList; bool build; bool auxMode; - bool stripLibraries = true; ActionTimer timer; // External tools @@ -175,22 +173,22 @@ struct Options // lib c++ path QString stdCppPath; - QString stdCppName = QStringLiteral("gnustl_shared"); + QString stdCppName = QStringLiteral("c++_shared"); // Build information QString androidPlatform; - QString architecture; - QString toolchainVersion; + QHash architectures; + QString currentArchitecture; QString toolchainPrefix; - QString toolPrefix; - bool useLLVM = false; QString ndkHost; // Package information DeploymentMechanism deploymentMechanism; QString packageName; QStringList extraLibs; + QHash archExtraLibs; QStringList extraPlugins; + QHash archExtraPlugins; // Signing information bool releasePackage; @@ -211,25 +209,36 @@ struct Options bool jarSigner; QString apkPath; - // Gdbserver - TriState gdbServer; - // Installation information bool installApk; bool uninstallApk; QString installLocation; - // Collected information + // Per architecture collected information + void clear(const QString &arch) + { + currentArchitecture = arch; + } typedef QPair BundledFile; - QList bundledFiles; - QList qtDependencies; - QStringList localLibs; + QHash> bundledFiles; + QHash> qtDependencies; + QHash localLibs; + bool usesOpenGL = false; + + // Per package collected information QStringList localJars; QStringList initClasses; QStringList permissions; QStringList features; }; +static const QHash elfArchitecures = { + {"aarch64", "arm64-v8a"}, + {"arm", "armeabi-v7a"}, + {"i386", "x86"}, + {"x86_64", "x86_64"} +}; + // Copy-pasted from qmake/library/ioutil.cpp inline static bool hasSpecialChars(const QString &arg, const uchar (&iqm)[16]) { @@ -301,6 +310,59 @@ static QString shellQuote(const QString &arg) return shellQuoteUnix(arg); } +QString architecureFromName(const QString &name) +{ + QRegExp architecture(QStringLiteral(".*_(.*)\\.so")); + if (!architecture.exactMatch(name)) + return {}; + return architecture.capturedTexts().last(); +} + +QString fileArchitecture(const Options &options, const QString &path) +{ + auto arch = architecureFromName(path); + if (!arch.isEmpty()) + return arch; + + QString readElf = QStringLiteral("%1/toolchains/%2/prebuilt/%3/bin/llvm-readobj").arg(options.ndkPath, + options.toolchainPrefix, + options.ndkHost); +#if defined(Q_OS_WIN32) + readElf += QStringLiteral(".exe"); +#endif + + if (!QFile::exists(readElf)) { + fprintf(stderr, "Command does not exist: %s\n", qPrintable(readElf)); + return {}; + } + + readElf = QStringLiteral("%1 -needed-libs %2").arg(shellQuote(readElf), shellQuote(path)); + + FILE *readElfCommand = openProcess(readElf); + if (!readElfCommand) { + fprintf(stderr, "Cannot execute command %s\n", qPrintable(readElf)); + return {}; + } + + char buffer[512]; + while (fgets(buffer, sizeof(buffer), readElfCommand) != nullptr) { + QByteArray line = QByteArray::fromRawData(buffer, qstrlen(buffer)); + QString library; + line = line.trimmed(); + if (line.startsWith("Arch: ")) { + auto it = elfArchitecures.find(line.mid(6)); + pclose(readElfCommand); + return it != elfArchitecures.constEnd() ? QString::fromLatin1(it.value()) : QString{}; + } + } + pclose(readElfCommand); + return {}; +} + +bool checkArchitecture(const Options &options, const QString &fileName) +{ + return fileArchitecture(options, fileName) == options.currentArchitecture; +} void deleteMissingFiles(const Options &options, const QDir &srcDir, const QDir &dstDir) { @@ -388,10 +450,6 @@ Options parseOptions() options.installLocation = arguments.at(++i); } else if (argument.compare(QLatin1String("--release"), Qt::CaseInsensitive) == 0) { options.releasePackage = true; - } else if (argument.compare(QLatin1String("--gdbserver"), Qt::CaseInsensitive) == 0) { - options.gdbServer = Options::True; - } else if (argument.compare(QLatin1String("--no-gdbserver"), Qt::CaseInsensitive) == 0) { - options.gdbServer = Options::False; } else if (argument.compare(QLatin1String("--jdk"), Qt::CaseInsensitive) == 0) { if (i + 1 == arguments.size()) options.helpRequested = true; @@ -462,8 +520,6 @@ Options parseOptions() options.generateAssetsFileList = false; } else if (argument.compare(QLatin1String("--aux-mode"), Qt::CaseInsensitive) == 0) { options.auxMode = true; - } else if (argument.compare(QLatin1String("--no-strip"), Qt::CaseInsensitive) == 0) { - options.stripLibraries = false; } } @@ -533,10 +589,6 @@ void printHelp() " --protected: Keystore has protected authentication path.\n" " --jarsigner: Force jarsigner usage, otherwise apksigner will be\n" " used if available.\n" - " --gdbserver: Adds the gdbserver to the package. By default the gdbserver\n" - " is bundled for debug pacakges.\n" - " --no-gdbserver: Prevents the gdbserver from being added to the package\n" - " By default the gdbserver is bundled for debug pacakges.\n" " --jdk : Used to find the jarsigner tool when used\n" " in combination with the --release argument. By default,\n" " an attempt is made to detect the tool using the JAVA_HOME and\n" @@ -549,7 +601,6 @@ void printHelp() " --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" - " --no-strip: Do not strip debug symbols from libraries.\n" " --apk : Path where to copy the built apk.\n" " --help: Displays this information.\n\n", qPrintable(QCoreApplication::arguments().at(0)) @@ -580,9 +631,10 @@ bool alwaysOverwritableFile(const QString &fileName) || fileName.endsWith(QLatin1String("/src/org/qtproject/qt5/android/bindings/QtActivity.java"))); } + bool copyFileIfNewer(const QString &sourceFileName, const QString &destinationFileName, - bool verbose, + const Options &options, bool forceOverwrite = false) { if (QFile::exists(destinationFileName)) { @@ -592,7 +644,7 @@ bool copyFileIfNewer(const QString &sourceFileName, if (!forceOverwrite && sourceFileInfo.lastModified() <= destinationFileInfo.lastModified() && !alwaysOverwritableFile(destinationFileName)) { - if (verbose) + if (options.verbose) fprintf(stdout, " -- Skipping file %s. Same or newer file already in place.\n", qPrintable(sourceFileName)); return true; } else { @@ -611,11 +663,10 @@ bool copyFileIfNewer(const QString &sourceFileName, if (!QFile::exists(destinationFileName) && !QFile::copy(sourceFileName, destinationFileName)) { fprintf(stderr, "Failed to copy %s to %s.\n", qPrintable(sourceFileName), qPrintable(destinationFileName)); return false; - } else if (verbose) { + } else if (options.verbose) { fprintf(stdout, " -- Copied %s\n", qPrintable(destinationFileName)); fflush(stdout); } - return true; } @@ -666,7 +717,7 @@ QString cleanPackageName(QString packageName) } } if (keywords.contains(word)) { - packageName.insert(next, QLatin1String("_")); + packageName.insert(next, QStringLiteral("_")); index = next + 1; } else { index = next; @@ -678,7 +729,7 @@ QString cleanPackageName(QString packageName) QString detectLatestAndroidPlatform(const QString &sdkPath) { - QDir dir(sdkPath + QLatin1String("/platforms")); + QDir dir(sdkPath + QStringLiteral("/platforms")); if (!dir.exists()) { fprintf(stderr, "Directory %s does not exist\n", qPrintable(dir.absolutePath())); return QString(); @@ -795,53 +846,22 @@ bool readInputFile(Options *options) } { - const QJsonValue applicationBinary = jsonObject.value(QStringLiteral("application-binary")); - if (applicationBinary.isUndefined()) { - fprintf(stderr, "No application binary defined in json file.\n"); - return false; - } - options->applicationBinary = applicationBinary.toString(); - - if (!QFile::exists(options->applicationBinary)) { - fprintf(stderr, "Cannot find application binary %s.\n", qPrintable(options->applicationBinary)); + const QJsonObject targetArchitectures = jsonObject.value(QStringLiteral("architectures")).toObject(); + if (targetArchitectures.isEmpty()) { + fprintf(stderr, "No target architecture defined in json file.\n"); return false; } - } - - { - const QJsonValue deploymentDependencies = jsonObject.value(QStringLiteral("deployment-dependencies")); - if (!deploymentDependencies.isUndefined()) { - QString deploymentDependenciesString = deploymentDependencies.toString(); - const auto dependencies = deploymentDependenciesString.splitRef(QLatin1Char(',')); - for (const QStringRef &dependency : dependencies) { - QString path = options->qtInstallDirectory + QLatin1Char('/') + dependency; - if (QFileInfo(path).isDir()) { - QDirIterator iterator(path, QDirIterator::Subdirectories); - while (iterator.hasNext()) { - iterator.next(); - if (iterator.fileInfo().isFile()) { - QString subPath = iterator.filePath(); - options->qtDependencies.append(QtDependency(subPath.mid(options->qtInstallDirectory.length() + 1), - subPath)); - } - } - } else { - options->qtDependencies.append(QtDependency(dependency.toString(), path)); - } + for (auto it = targetArchitectures.constBegin(); it != targetArchitectures.constEnd(); ++it) { + if (it.value().isUndefined()) { + fprintf(stderr, "Invalid architecure.\n"); + return false; } + if (it.value().isNull()) + continue; + options->architectures.insert(it.key(), it.value().toString()); } } - - { - const QJsonValue targetArchitecture = jsonObject.value(QStringLiteral("target-architecture")); - if (targetArchitecture.isUndefined()) { - fprintf(stderr, "No target architecture defined in json file.\n"); - return false; - } - options->architecture = targetArchitecture.toString(); - } - { const QJsonValue ndk = jsonObject.value(QStringLiteral("ndk")); if (ndk.isUndefined()) { @@ -851,11 +871,6 @@ bool readInputFile(Options *options) options->ndkPath = ndk.toString(); } - { - const QJsonValue value = jsonObject.value(QStringLiteral("useLLVM")); - options->useLLVM = value.toBool(false); - } - { const QJsonValue toolchainPrefix = jsonObject.value(QStringLiteral("toolchain-prefix")); if (toolchainPrefix.isUndefined()) { @@ -865,25 +880,6 @@ bool readInputFile(Options *options) options->toolchainPrefix = toolchainPrefix.toString(); } - { - const QJsonValue toolPrefix = jsonObject.value(QStringLiteral("tool-prefix")); - if (toolPrefix.isUndefined()) { - fprintf(stderr, "Warning: No tool prefix defined in json file.\n"); - options->toolPrefix = options->toolchainPrefix; - } else { - options->toolPrefix = toolPrefix.toString(); - } - } - - if (!options->useLLVM) { - const QJsonValue toolchainVersion = jsonObject.value(QStringLiteral("toolchain-version")); - if (toolchainVersion.isUndefined()) { - fprintf(stderr, "No toolchain version defined in json file.\n"); - return false; - } - options->toolchainVersion = toolchainVersion.toString(); - } - { const QJsonValue ndkHost = jsonObject.value(QStringLiteral("ndk-host")); if (ndkHost.isUndefined()) { @@ -893,10 +889,6 @@ bool readInputFile(Options *options) options->ndkHost = ndkHost.toString(); } - options->packageName = packageNameFromAndroidManifest(options->androidSourceDirectory + QLatin1String("/AndroidManifest.xml")); - if (options->packageName.isEmpty()) - options->packageName = cleanPackageName(QString::fromLatin1("org.qtproject.example.%1").arg(QFileInfo(options->applicationBinary).baseName().mid(sizeof("lib") - 1))); - { const QJsonValue extraLibs = jsonObject.value(QStringLiteral("android-extra-libs")); if (!extraLibs.isUndefined()) @@ -916,12 +908,6 @@ bool readInputFile(Options *options) return false; } options->stdCppPath = stdcppPath.toString(); - auto name = QFileInfo(options->stdCppPath).baseName(); - if (!name.startsWith(QLatin1String("lib"))) { - fprintf(stderr, "Invalid STD C++ library name.\n"); - return false; - } - options->stdCppName = name.mid(3); } { @@ -935,10 +921,68 @@ bool readInputFile(Options *options) if (!qmlImportPaths.isUndefined()) options->qmlImportPaths = qmlImportPaths.toString().split(QLatin1Char(',')); } + + { + const QJsonValue applicationBinary = jsonObject.value(QStringLiteral("application-binary")); + if (applicationBinary.isUndefined()) { + fprintf(stderr, "No application binary defined in json file.\n"); + return false; + } + options->applicationBinary = applicationBinary.toString(); + if (options->build) { + for (auto it = options->architectures.constBegin(); it != options->architectures.constEnd(); ++it) { + if (!QFile::exists(QStringLiteral("%1/libs/%2/lib%3_%2.so").arg(options->outputDirectory, it.key(), options->applicationBinary))) { + fprintf(stderr, "Cannot find application binary %s.\n", qPrintable(options->applicationBinary)); + return false; + } + } + } + } + + { + const QJsonValue deploymentDependencies = jsonObject.value(QStringLiteral("deployment-dependencies")); + if (!deploymentDependencies.isUndefined()) { + QString deploymentDependenciesString = deploymentDependencies.toString(); + const auto dependencies = deploymentDependenciesString.splitRef(QLatin1Char(',')); + for (const QStringRef &dependency : dependencies) { + QString path = options->qtInstallDirectory + QLatin1Char('/') + dependency; + if (QFileInfo(path).isDir()) { + QDirIterator iterator(path, QDirIterator::Subdirectories); + while (iterator.hasNext()) { + iterator.next(); + if (iterator.fileInfo().isFile()) { + QString subPath = iterator.filePath(); + auto arch = fileArchitecture(*options, subPath); + if (!arch.isEmpty()) { + options->qtDependencies[arch].append(QtDependency(subPath.mid(options->qtInstallDirectory.length() + 1), + subPath)); + } else if (options->verbose) { + fprintf(stderr, "Skipping \"%s\", unknown architecture\n", qPrintable(subPath)); + fflush(stderr); + } + } + } + } else { + auto arch = fileArchitecture(*options, path); + if (!arch.isEmpty()) { + options->qtDependencies[arch].append(QtDependency(dependency.toString(), path)); + } else if (options->verbose) { + fprintf(stderr, "Skipping \"%s\", unknown architecture\n", qPrintable(path)); + fflush(stderr); + } + } + } + } + } + + options->packageName = packageNameFromAndroidManifest(options->androidSourceDirectory + QStringLiteral("/AndroidManifest.xml")); + if (options->packageName.isEmpty()) + options->packageName = cleanPackageName(QStringLiteral("org.qtproject.example.%1").arg(options->applicationBinary)); + return true; } -bool copyFiles(const QDir &sourceDirectory, const QDir &destinationDirectory, bool verbose, bool forceOverwrite = false) +bool copyFiles(const QDir &sourceDirectory, const QDir &destinationDirectory, const Options &options, bool forceOverwrite = false) { const QFileInfoList entries = sourceDirectory.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); for (const QFileInfo &entry : entries) { @@ -949,11 +993,11 @@ bool copyFiles(const QDir &sourceDirectory, const QDir &destinationDirectory, bo return false; } - if (!copyFiles(dir, QDir(destinationDirectory.path() + QLatin1String("/") + dir.dirName()), verbose, forceOverwrite)) + if (!copyFiles(dir, QDir(destinationDirectory.path() + QStringLiteral("/") + dir.dirName()), options, forceOverwrite)) return false; } else { QString destination = destinationDirectory.absoluteFilePath(entry.fileName()); - if (!copyFileIfNewer(entry.absoluteFilePath(), destination, verbose, forceOverwrite)) + if (!copyFileIfNewer(entry.absoluteFilePath(), destination, options, forceOverwrite)) return false; } } @@ -993,7 +1037,7 @@ bool copyAndroidTemplate(const Options &options, const QString &androidTemplate, return false; } - return copyFiles(sourceDirectory, QDir(outDir), options.verbose); + return copyFiles(sourceDirectory, QDir(outDir), options); } bool copyGradleTemplate(const Options &options) @@ -1010,7 +1054,7 @@ bool copyGradleTemplate(const Options &options) return false; } - return copyFiles(sourceDirectory, QDir(outDir), options.verbose); + return copyFiles(sourceDirectory, QDir(outDir), options); } bool copyAndroidTemplate(const Options &options) @@ -1041,38 +1085,42 @@ bool copyAndroidSources(const Options &options) return false; } - return copyFiles(sourceDirectory, QDir(options.outputDirectory), options.verbose, true); + return copyFiles(sourceDirectory, QDir(options.outputDirectory), options, true); } -bool copyAndroidExtraLibs(const Options &options) +bool copyAndroidExtraLibs(Options *options) { - if (options.extraLibs.isEmpty()) + if (options->extraLibs.isEmpty()) return true; - if (options.verbose) - fprintf(stdout, "Copying %d external libraries to package.\n", options.extraLibs.size()); + if (options->verbose) + fprintf(stdout, "Copying %d external libraries to package.\n", options->extraLibs.size()); - for (const QString &extraLib : options.extraLibs) { + for (const QString &extraLib : options->extraLibs) { QFileInfo extraLibInfo(extraLib); if (!extraLibInfo.exists()) { fprintf(stderr, "External library %s does not exist!\n", qPrintable(extraLib)); return false; } - - if (!extraLibInfo.fileName().startsWith(QLatin1String("lib")) || extraLibInfo.suffix() != QLatin1String("so")) { + if (!checkArchitecture(*options, extraLibInfo.filePath())) { + if (options->verbose) + fprintf(stdout, "Skipping \"%s\", architecture mismatch.\n", qPrintable(extraLib)); + continue; + } + if (!extraLibInfo.fileName().startsWith(QStringLiteral("lib")) || extraLibInfo.suffix() != QStringLiteral("so")) { fprintf(stderr, "The file name of external library %s must begin with \"lib\" and end with the suffix \".so\".\n", qPrintable(extraLib)); return false; } - - QString destinationFile(options.outputDirectory - + QLatin1String("/libs/") - + options.architecture + QString destinationFile(options->outputDirectory + + QStringLiteral("/libs/") + + options->currentArchitecture + QLatin1Char('/') + extraLibInfo.fileName()); - if (!copyFileIfNewer(extraLib, destinationFile, options.verbose)) + if (!copyFileIfNewer(extraLib, destinationFile, *options)) return false; + options->archExtraLibs[options->currentArchitecture] += extraLib; } return true; @@ -1093,15 +1141,15 @@ QStringList allFilesInside(const QDir& current, const QDir& rootDir) return result; } -bool copyAndroidExtraResources(const Options &options) +bool copyAndroidExtraResources(Options *options) { - if (options.extraPlugins.isEmpty()) + if (options->extraPlugins.isEmpty()) return true; - if (options.verbose) - fprintf(stdout, "Copying %d external resources to package.\n", options.extraPlugins.size()); + if (options->verbose) + fprintf(stdout, "Copying %d external resources to package.\n", options->extraPlugins.size()); - for (const QString &extraResource : options.extraPlugins) { + for (const QString &extraResource : options->extraPlugins) { QFileInfo extraResourceInfo(extraResource); if (!extraResourceInfo.exists() || !extraResourceInfo.isDir()) { fprintf(stderr, "External resource %s does not exist or not a correct directory!\n", qPrintable(extraResource)); @@ -1109,20 +1157,22 @@ bool copyAndroidExtraResources(const Options &options) } QDir resourceDir(extraResource); - QString assetsDir = options.outputDirectory + QStringLiteral("/assets/") + resourceDir.dirName() + QLatin1Char('/'); - QString libsDir = options.outputDirectory + QStringLiteral("/libs/") + options.architecture + QLatin1Char('/'); + QString assetsDir = options->outputDirectory + QStringLiteral("/assets/") + resourceDir.dirName() + QLatin1Char('/'); + QString libsDir = options->outputDirectory + QStringLiteral("/libs/") + options->currentArchitecture + QLatin1Char('/'); const QStringList files = allFilesInside(resourceDir, resourceDir); for (const QString &resourceFile : files) { QString originFile(resourceDir.filePath(resourceFile)); QString destinationFile; - if (!resourceFile.endsWith(QLatin1String(".so"))) { + if (!resourceFile.endsWith(QStringLiteral(".so"))) { destinationFile = assetsDir + resourceFile; } else { + if (!checkArchitecture(*options, originFile)) + continue; destinationFile = libsDir + QStringLiteral("/lib") + QString(resourceDir.dirName() + QLatin1Char('/') + resourceFile).replace(QLatin1Char('/'), QLatin1Char('_')); + options->archExtraPlugins[options->currentArchitecture] += resourceFile; } - - if (!copyFileIfNewer(originFile, destinationFile, options.verbose)) + if (!copyFileIfNewer(originFile, destinationFile, *options)) return false; } } @@ -1174,75 +1224,118 @@ bool updateFile(const QString &fileName, const QHash &replacem } -bool updateLibsXml(const Options &options) +bool updateLibsXml(Options *options) { - if (options.verbose) + if (options->verbose) fprintf(stdout, " -- res/values/libs.xml\n"); - QString fileName = options.outputDirectory + QLatin1String("/res/values/libs.xml"); + QString fileName = options->outputDirectory + QStringLiteral("/res/values/libs.xml"); if (!QFile::exists(fileName)) { fprintf(stderr, "Cannot find %s in prepared packaged. This file is required.\n", qPrintable(fileName)); return false; } - QString libsPath = QLatin1String("libs/") + options.architecture + QLatin1Char('/'); - - QString qtLibs = QLatin1String("") + options.stdCppName + QLatin1String("\n"); + QString qtLibs; QString bundledInLibs; QString bundledInAssets; - for (const Options::BundledFile &bundledFile : options.bundledFiles) { - if (bundledFile.second.startsWith(QLatin1String("lib/"))) { - QString s = bundledFile.second.mid(sizeof("lib/lib") - 1); - s.chop(sizeof(".so") - 1); - qtLibs += QString::fromLatin1("%1\n").arg(s); - } else if (bundledFile.first.startsWith(libsPath)) { - QString s = bundledFile.first.mid(libsPath.length()); - bundledInLibs += QString::fromLatin1("%1:%2\n") - .arg(s).arg(bundledFile.second); - } else if (bundledFile.first.startsWith(QLatin1String("assets/"))) { - QString s = bundledFile.first.mid(sizeof("assets/") - 1); - bundledInAssets += QString::fromLatin1("%1:%2\n") - .arg(s).arg(bundledFile.second); + QString allLocalLibs; + QString extraLibs; + + for (auto it = options->architectures.constBegin(); it != options->architectures.constEnd(); ++it) { + QString libsPath = QStringLiteral("libs/") + it.key() + QLatin1Char('/'); + + qtLibs += QStringLiteral(" %1;%2\n").arg(it.key(), options->stdCppName); + for (const Options::BundledFile &bundledFile : options->bundledFiles[it.key()]) { + if (bundledFile.second.startsWith(QStringLiteral("lib/"))) { + QString s = bundledFile.second.mid(sizeof("lib/lib") - 1); + s.chop(sizeof(".so") - 1); + qtLibs += QStringLiteral(" %1;%2\n").arg(it.key(), s); + } else if (bundledFile.first.startsWith(libsPath)) { + QString s = bundledFile.first.mid(libsPath.length()); + bundledInLibs += QString::fromLatin1(" %1;%2:%3\n") + .arg(it.key(), s, bundledFile.second); + } else if (bundledFile.first.startsWith(QStringLiteral("assets/"))) { + QString s = bundledFile.first.mid(sizeof("assets/") - 1); + bundledInAssets += QString::fromLatin1(" %1:%2\n") + .arg(s).arg(bundledFile.second); + } } - } - if (!options.extraPlugins.isEmpty()) { - for (const QString &extraRes : options.extraPlugins) { - QDir resourceDir(extraRes); - const QStringList files = allFilesInside(resourceDir, resourceDir); - for (const QString &file : files) { - QString destinationPath = resourceDir.dirName() + QLatin1Char('/') + file; - if (!file.endsWith(QLatin1String(".so"))) { - bundledInAssets += QStringLiteral("%1:%1\n") - .arg(destinationPath); - } else { - bundledInLibs += QStringLiteral("lib%1:%2\n") - .arg(QString(destinationPath).replace(QLatin1Char('/'), QLatin1Char('_'))) - .arg(destinationPath); + if (!options->archExtraPlugins[it.key()].isEmpty()) { + for (const QString &extraRes : options->archExtraPlugins[it.key()]) { + QDir resourceDir(extraRes); + const QStringList files = allFilesInside(resourceDir, resourceDir); + for (const QString &file : files) { + QString destinationPath = resourceDir.dirName() + QLatin1Char('/') + file; + if (!file.endsWith(QStringLiteral(".so"))) { + bundledInAssets += QStringLiteral(" %1:%1\n") + .arg(destinationPath); + } else { + bundledInLibs += QStringLiteral(" %1;lib%2:%3\n") + .arg(it.key(), + QString(destinationPath).replace(QLatin1Char('/'), QLatin1Char('_')), + destinationPath); + } } } } - } - QHash replacements; - replacements[QLatin1String("")] = qtLibs; + if (!options->archExtraLibs[it.key()].isEmpty()) { + for (const QString &extraLib : options->archExtraLibs[it.key()]) { + QFileInfo extraLibInfo(extraLib); + QString name = extraLibInfo.fileName().mid(sizeof("lib") - 1); + name.chop(sizeof(".so") - 1); + extraLibs += QStringLiteral(" %1;%2").arg(it.key(), name); + } + } - if (options.deploymentMechanism == Options::Bundled) { - replacements[QLatin1String("")] = bundledInLibs; - replacements[QLatin1String("")] = bundledInAssets; - } + QStringList localLibs; + localLibs = options->localLibs[it.key()]; + // If .pro file overrides dependency detection, we need to see which platform plugin they picked + if (localLibs.isEmpty()) { + QString plugin; + for (const QtDependency &qtDependency : options->qtDependencies[it.key()]) { + if (qtDependency.relativePath.endsWith(QStringLiteral("libqtforandroid.so")) + || qtDependency.relativePath.endsWith(QStringLiteral("libqtforandroidGL.so"))) { + if (!plugin.isEmpty() && plugin != qtDependency.relativePath) { + fprintf(stderr, "Both platform plugins libqtforandroid.so and libqtforandroidGL.so included in package. Please include only one.\n"); + return false; + } - QString extraLibs; - if (!options.extraLibs.isEmpty()) { - for (const QString extraLib : options.extraLibs) { - QFileInfo extraLibInfo(extraLib); - QString name = extraLibInfo.fileName().mid(sizeof("lib") - 1); - name.chop(sizeof(".so") - 1); + plugin = qtDependency.relativePath; + } + if (qtDependency.relativePath.contains(QStringLiteral("libQt5OpenGL")) + || qtDependency.relativePath.contains(QStringLiteral("libQt5Quick"))) { + options->usesOpenGL |= true; + break; + } + } - extraLibs += QLatin1String("") + name + QLatin1String("\n"); + if (plugin.isEmpty()) { + fflush(stdout); + fprintf(stderr, "No platform plugin, neither libqtforandroid.so or libqtforandroidGL.so, included in package. Please include one.\n"); + fflush(stderr); + return false; + } + + localLibs.append(plugin); + if (options->verbose) + fprintf(stdout, " -- Using platform plugin %s\n", qPrintable(plugin)); } + allLocalLibs += QStringLiteral(" %1;%2\n").arg(it.key(), localLibs.join(QLatin1Char(':')) + .replace(QStringLiteral("lib/"), QString{}) + .replace(QLatin1Char('/'), QLatin1Char('_'))); + } + + QHash replacements; + replacements[QStringLiteral("")] += qtLibs.trimmed(); + replacements[QStringLiteral("")] = allLocalLibs.trimmed(); + replacements[QStringLiteral("")] = extraLibs.trimmed(); + + if (options->deploymentMechanism == Options::Bundled) { + replacements[QStringLiteral("")] += bundledInLibs.trimmed(); + replacements[QStringLiteral("")] += bundledInAssets.trimmed(); } - replacements[QLatin1String("")] = extraLibs; if (!updateFile(fileName, replacements)) return false; @@ -1256,9 +1349,9 @@ bool updateStringsXml(const Options &options) fprintf(stdout, " -- res/values/strings.xml\n"); QHash replacements; - replacements[QStringLiteral("")] = QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1); + replacements[QStringLiteral("")] = options.applicationBinary; - QString fileName = options.outputDirectory + QLatin1String("/res/values/strings.xml"); + QString fileName = options.outputDirectory + QStringLiteral("/res/values/strings.xml"); if (!QFile::exists(fileName)) { if (options.verbose) fprintf(stdout, " -- Create strings.xml since it's missing.\n"); @@ -1268,7 +1361,7 @@ bool updateStringsXml(const Options &options) return false; } file.write(QByteArray("") - .append(QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1).toLatin1()) + .append(options.applicationBinary.toLatin1()) .append("\n")); return true; } @@ -1284,71 +1377,34 @@ bool updateAndroidManifest(Options &options) if (options.verbose) fprintf(stdout, " -- AndroidManifest.xml \n"); - QStringList localLibs = options.localLibs; - - // If .pro file overrides dependency detection, we need to see which platform plugin they picked - if (localLibs.isEmpty()) { - QString plugin; - for (const QtDependency &qtDependency : qAsConst(options.qtDependencies)) { - if (qtDependency.relativePath.endsWith(QLatin1String("libqtforandroid.so")) - || qtDependency.relativePath.endsWith(QLatin1String("libqtforandroidGL.so"))) { - if (!plugin.isEmpty() && plugin != qtDependency.relativePath) { - fprintf(stderr, "Both platform plugins libqtforandroid.so and libqtforandroidGL.so included in package. Please include only one.\n"); - return false; - } - - plugin = qtDependency.relativePath; - } - } - - if (plugin.isEmpty()) { - fprintf(stderr, "No platform plugin, neither libqtforandroid.so or libqtforandroidGL.so, included in package. Please include one.\n"); - return false; - } - - localLibs.append(plugin); - if (options.verbose) - fprintf(stdout, " -- Using platform plugin %s\n", qPrintable(plugin)); - } - - bool usesGL = false; - for (const QtDependency &qtDependency : qAsConst(options.qtDependencies)) { - if (qtDependency.relativePath.endsWith(QLatin1String("libQt5OpenGL.so")) - || qtDependency.relativePath.endsWith(QLatin1String("libQt5Quick.so"))) { - usesGL = true; - break; - } - } - options.localJars.removeDuplicates(); options.initClasses.removeDuplicates(); QHash replacements; - replacements[QLatin1String("-- %%INSERT_APP_NAME%% --")] = QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1); - replacements[QLatin1String("-- %%INSERT_APP_LIB_NAME%% --")] = QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1); - replacements[QLatin1String("-- %%INSERT_LOCAL_LIBS%% --")] = localLibs.join(QLatin1Char(':')); - replacements[QLatin1String("-- %%INSERT_LOCAL_JARS%% --")] = options.localJars.join(QLatin1Char(':')); - replacements[QLatin1String("-- %%INSERT_INIT_CLASSES%% --")] = options.initClasses.join(QLatin1Char(':')); - replacements[QLatin1String("-- %%INSERT_VERSION_NAME%% --")] = options.versionName; - replacements[QLatin1String("-- %%INSERT_VERSION_CODE%% --")] = options.versionCode; - replacements[QLatin1String("package=\"org.qtproject.example\"")] = QString::fromLatin1("package=\"%1\"").arg(options.packageName); - replacements[QLatin1String("-- %%BUNDLE_LOCAL_QT_LIBS%% --")] - = (options.deploymentMechanism == Options::Bundled) ? QString::fromLatin1("1") : QString::fromLatin1("0"); - replacements[QLatin1String("-- %%USE_LOCAL_QT_LIBS%% --")] - = (options.deploymentMechanism != Options::Ministro) ? QString::fromLatin1("1") : QString::fromLatin1("0"); + replacements[QStringLiteral("-- %%INSERT_APP_NAME%% --")] = options.applicationBinary; + replacements[QStringLiteral("-- %%INSERT_APP_LIB_NAME%% --")] = options.applicationBinary; + replacements[QStringLiteral("-- %%INSERT_LOCAL_JARS%% --")] = options.localJars.join(QLatin1Char(':')); + replacements[QStringLiteral("-- %%INSERT_INIT_CLASSES%% --")] = options.initClasses.join(QLatin1Char(':')); + replacements[QStringLiteral("-- %%INSERT_VERSION_NAME%% --")] = options.versionName; + replacements[QStringLiteral("-- %%INSERT_VERSION_CODE%% --")] = options.versionCode; + replacements[QStringLiteral("package=\"org.qtproject.example\"")] = QStringLiteral("package=\"%1\"").arg(options.packageName); + replacements[QStringLiteral("-- %%BUNDLE_LOCAL_QT_LIBS%% --")] + = (options.deploymentMechanism == Options::Bundled) ? QStringLiteral("1") : QStringLiteral("0"); + replacements[QStringLiteral("-- %%USE_LOCAL_QT_LIBS%% --")] + = (options.deploymentMechanism != Options::Ministro) ? QStringLiteral("1") : QStringLiteral("0"); QString permissions; for (const QString &permission : qAsConst(options.permissions)) - permissions += QString::fromLatin1(" \n").arg(permission); - replacements[QLatin1String("")] = permissions; + permissions += QStringLiteral(" \n").arg(permission); + replacements[QStringLiteral("")] = permissions.trimmed(); QString features; for (const QString &feature : qAsConst(options.features)) features += QStringLiteral(" \n").arg(feature); - if (usesGL) + if (options.usesOpenGL) features += QStringLiteral(" "); - replacements[QLatin1String("")] = features; + replacements[QStringLiteral("")] = features.trimmed(); QString androidManifestPath = options.outputDirectory + QLatin1String("/AndroidManifest.xml"); if (!updateFile(androidManifestPath, replacements)) @@ -1409,7 +1465,7 @@ bool updateAndroidFiles(Options &options) if (options.verbose) fprintf(stdout, "Updating Android package files with project settings.\n"); - if (!updateLibsXml(options)) + if (!updateLibsXml(&options)) return false; if (!updateAndroidManifest(options)) @@ -1466,7 +1522,7 @@ bool readAndroidDependencyXml(Options *options, QSet *usedDependencies, QSet *remainingDependencies) { - QString androidDependencyName = absoluteFilePath(options, QString::fromLatin1("/lib/%1-android-dependencies.xml").arg(moduleName)); + QString androidDependencyName = absoluteFilePath(options, QStringLiteral("/lib/%1-android-dependencies.xml").arg(moduleName)); QFile androidDependencyFile(androidDependencyName); if (androidDependencyFile.exists()) { @@ -1505,7 +1561,7 @@ bool readAndroidDependencyXml(Options *options, if (options->verbose) fprintf(stdout, "Appending dependency from xml: %s\n", qPrintable(fileName.relativePath)); - options->qtDependencies.append(fileName); + options->qtDependencies[options->currentArchitecture].append(fileName); } } else if (reader.name() == QLatin1String("jar")) { int bundling = reader.attributes().value(QLatin1String("bundling")).toInt(); @@ -1513,7 +1569,7 @@ bool readAndroidDependencyXml(Options *options, if (bundling == (options->deploymentMechanism == Options::Bundled)) { QtDependency dependency(fileName, absoluteFilePath(options, fileName)); if (!usedDependencies->contains(dependency.absolutePath)) { - options->qtDependencies.append(dependency); + options->qtDependencies[options->currentArchitecture].append(dependency); usedDependencies->insert(dependency.absolutePath); } } @@ -1529,15 +1585,15 @@ bool readAndroidDependencyXml(Options *options, if (reader.attributes().hasAttribute(QLatin1String("replaces"))) { QString replaces = reader.attributes().value(QLatin1String("replaces")).toString(); for (int i=0; ilocalLibs.size(); ++i) { - if (options->localLibs.at(i) == replaces) { - options->localLibs[i] = fileName; + if (options->localLibs[options->currentArchitecture].at(i) == replaces) { + options->localLibs[options->currentArchitecture][i] = fileName; break; } } } else if (!fileName.isEmpty()) { - options->localLibs.append(fileName); + options->localLibs[options->currentArchitecture].append(fileName); } - if (fileName.endsWith(QLatin1String(".so"))) { + if (fileName.endsWith(QStringLiteral(".so")) && checkArchitecture(*options, fileName)) { remainingDependencies->insert(fileName); } } else if (reader.name() == QLatin1String("permission")) { @@ -1557,26 +1613,19 @@ bool readAndroidDependencyXml(Options *options, } else if (options->verbose) { fprintf(stdout, "No android dependencies for %s\n", qPrintable(moduleName)); } + options->permissions.removeDuplicates(); + options->features.removeDuplicates(); return true; } QStringList getQtLibsFromElf(const Options &options, const QString &fileName) { - QString readElf = options.ndkPath - + QLatin1String("/toolchains/") - + options.toolchainPrefix; - - if (!options.useLLVM) - readElf += QLatin1Char('-') + options.toolchainVersion; - - readElf += QLatin1String("/prebuilt/") - + options.ndkHost - + QLatin1String("/bin/") - + options.toolPrefix + - (options.useLLVM ? QLatin1String("-readobj") : QLatin1String("-readelf")); + QString readElf = QStringLiteral("%1/toolchains/%2/prebuilt/%3/bin/llvm-readobj").arg(options.ndkPath, + options.toolchainPrefix, + options.ndkHost); #if defined(Q_OS_WIN32) - readElf += QLatin1String(".exe"); + readElf += QStringLiteral(".exe"); #endif if (!QFile::exists(readElf)) { @@ -1584,14 +1633,11 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName) return QStringList(); } - if (options.useLLVM) - readElf = QString::fromLatin1("%1 -needed-libs %2").arg(shellQuote(readElf), shellQuote(fileName)); - else - readElf = QString::fromLatin1("%1 -d -W %2").arg(shellQuote(readElf), shellQuote(fileName)); + readElf = QStringLiteral("%1 -needed-libs %2").arg(shellQuote(readElf), shellQuote(fileName)); FILE *readElfCommand = openProcess(readElf); if (!readElfCommand) { - fprintf(stderr, "Cannot execute command %s", qPrintable(readElf)); + fprintf(stderr, "Cannot execute command %s\n", qPrintable(readElf)); return QStringList(); } @@ -1599,23 +1645,26 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName) bool readLibs = false; char buffer[512]; - while (fgets(buffer, sizeof(buffer), readElfCommand) != 0) { + while (fgets(buffer, sizeof(buffer), readElfCommand) != nullptr) { QByteArray line = QByteArray::fromRawData(buffer, qstrlen(buffer)); QString library; - if (options.useLLVM) { - line = line.trimmed(); - if (!readLibs) { - readLibs = line.startsWith("NeededLibraries"); - continue; + line = line.trimmed(); + if (!readLibs) { + if (line.startsWith("Arch: ")) { + auto it = elfArchitecures.find(line.mid(6)); + if (it == elfArchitecures.constEnd() || *it != options.currentArchitecture.toLatin1()) { + if (options.verbose) + fprintf(stdout, "Skipping \"%s\", architecture mismatch\n", qPrintable(fileName)); + return {}; + } } - if (!line.startsWith("lib")) - continue; - library = QString::fromLatin1(line); - } else if (line.contains("(NEEDED)") && line.contains("Shared library:")) { - const int pos = line.lastIndexOf('[') + 1; - library = QString::fromLatin1(line.mid(pos, line.length() - pos - 2)); + readLibs = line.startsWith("NeededLibraries"); + continue; } - QString libraryName = QLatin1String("lib/") + library; + if (!line.startsWith("lib")) + continue; + library = QString::fromLatin1(line); + QString libraryName = QStringLiteral("lib/") + library; if (QFile::exists(absoluteFilePath(&options, libraryName))) ret += libraryName; } @@ -1653,7 +1702,7 @@ bool readDependenciesFromElf(Options *options, return false; } - options->qtDependencies.append(QtDependency(dependency, absoluteDependencyPath)); + options->qtDependencies[options->currentArchitecture].append(QtDependency(dependency, absoluteDependencyPath)); if (options->verbose) fprintf(stdout, "Appending dependency: %s\n", qPrintable(dependency)); dependenciesToCheck.append(dependency); @@ -1797,10 +1846,10 @@ bool scanImports(Options *options, QSet *usedDependencies) fprintf(stdout, " -- Appending dependency found by qmlimportscanner: %s\n", qPrintable(fileName.absolutePath)); // Put all imports in default import path in assets - fileName.relativePath.prepend(QLatin1String("qml/")); - options->qtDependencies.append(fileName); + fileName.relativePath.prepend(QStringLiteral("qml/")); + options->qtDependencies[options->currentArchitecture].append(fileName); - if (fileName.absolutePath.endsWith(QLatin1String(".so"))) { + if (fileName.absolutePath.endsWith(QStringLiteral(".so")) && checkArchitecture(*options, fileName.absolutePath)) { QSet remainingDependencies; if (!readDependenciesFromElf(options, fileName.absolutePath, usedDependencies, &remainingDependencies)) return false; @@ -1819,7 +1868,7 @@ bool readDependencies(Options *options) fprintf(stdout, "Detecting dependencies of application.\n"); // Override set in .pro file - if (!options->qtDependencies.isEmpty()) { + if (!options->qtDependencies[options->currentArchitecture].isEmpty()) { if (options->verbose) fprintf(stdout, "\tDependencies explicitly overridden in .pro file. No detection needed.\n"); return true; @@ -1829,11 +1878,7 @@ bool readDependencies(Options *options) QSet remainingDependencies; // Add dependencies of application binary first - if (!readDependenciesFromElf(options, options->applicationBinary, &usedDependencies, &remainingDependencies)) - return false; - - // Jam in the dependencies of the platform plugin, since the application will crash without it - if (!readDependenciesFromElf(options, options->qtInstallDirectory + QLatin1String("/plugins/platforms/android/libqtforandroid.so"), &usedDependencies, &remainingDependencies)) + if (!readDependenciesFromElf(options, QStringLiteral("%1/libs/%2/lib%3_%2.so").arg(options->outputDirectory, options->currentArchitecture, options->applicationBinary), &usedDependencies, &remainingDependencies)) return false; while (!remainingDependencies.isEmpty()) { @@ -1853,14 +1898,14 @@ bool readDependencies(Options *options) } } - QStringList::iterator it = options->localLibs.begin(); - while (it != options->localLibs.end()) { + QStringList::iterator it = options->localLibs[options->currentArchitecture].begin(); + while (it != options->localLibs[options->currentArchitecture].end()) { QStringList unmetDependencies; if (!goodToCopy(options, absoluteFilePath(options, *it), &unmetDependencies)) { fprintf(stdout, "Skipping %s due to unmet dependencies: %s\n", qPrintable(*it), qPrintable(unmetDependencies.join(QLatin1Char(',')))); - it = options->localLibs.erase(it); + it = options->localLibs[options->currentArchitecture].erase(it); } else { ++it; } @@ -1872,94 +1917,33 @@ bool readDependencies(Options *options) return true; } -bool stripFile(const Options &options, const QString &fileName) -{ - QString strip = options.ndkPath - + QLatin1String("/toolchains/") - + options.toolchainPrefix; - - if (!options.useLLVM) - strip += QLatin1Char('-') + options.toolchainVersion; - - strip += QLatin1String("/prebuilt/") - + options.ndkHost - + QLatin1String("/bin/") - + options.toolPrefix - + QLatin1String("-strip"); -#if defined(Q_OS_WIN32) - strip += QLatin1String(".exe"); -#endif - - if (!QFile::exists(strip)) { - fprintf(stderr, "Command does not exist: %s\n", qPrintable(strip)); - return false; - } - - if (options.useLLVM) - strip = QString::fromLatin1("%1 -strip-all %2").arg(shellQuote(strip), shellQuote(fileName)); - else - strip = QString::fromLatin1("%1 %2").arg(shellQuote(strip), shellQuote(fileName)); - - FILE *stripCommand = openProcess(strip); - if (stripCommand == 0) { - fprintf(stderr, "Cannot execute command %s", qPrintable(strip)); - return false; - } - - pclose(stripCommand); - - return true; -} - -bool stripLibraries(const Options &options) +bool containsApplicationBinary(Options *options) { - if (!options.stripLibraries) + if (!options->build) return true; - if (options.verbose) - fprintf(stdout, "Stripping libraries to minimize size.\n"); - - - QString libraryPath = options.outputDirectory - + QLatin1String("/libs/") - + options.architecture; - const QStringList libraries = QDir(libraryPath).entryList(QDir::Files); - for (const QString &library : libraries) { - if (library.endsWith(QLatin1String(".so"))) { - if (!stripFile(options, libraryPath + QLatin1Char('/') + library)) - return false; - } - } - - return true; -} - -bool containsApplicationBinary(const Options &options) -{ - if (options.verbose) + if (options->verbose) fprintf(stdout, "Checking if application binary is in package.\n"); - QFileInfo applicationBinary(options.applicationBinary); - QString destinationFileName = options.outputDirectory - + QLatin1String("/libs/") - + options.architecture - + QLatin1Char('/') - + applicationBinary.fileName(); + QFileInfo applicationBinary(options->applicationBinary); + QString applicationFileName = QStringLiteral("lib%1_%2.so").arg(options->applicationBinary, + options->currentArchitecture); - if (!QFile::exists(destinationFileName)) { + QString applicationPath = QStringLiteral("%1/libs/%2/%3").arg(options->outputDirectory, + options->currentArchitecture, + applicationFileName); + if (!QFile::exists(applicationPath)) { #if defined(Q_OS_WIN32) QLatin1String makeTool("mingw32-make"); // Only Mingw host builds supported on Windows currently #else QLatin1String makeTool("make"); #endif - fprintf(stderr, "Application binary is not in output directory: %s. Please run '%s install INSTALL_ROOT=%s' first.\n", - qPrintable(destinationFileName), + qPrintable(applicationFileName), qPrintable(makeTool), - qPrintable(options.outputDirectory)); + qPrintable(options->outputDirectory)); return false; } - return true; } @@ -1997,10 +1981,13 @@ bool goodToCopy(const Options *options, const QString &file, QStringList *unmetD if (!file.endsWith(QLatin1String(".so"))) return true; + if (!checkArchitecture(*options, file)) + return false; + bool ret = true; const auto libs = getQtLibsFromElf(*options, file); for (const QString &lib : libs) { - if (!options->qtDependencies.contains(QtDependency(lib, absoluteFilePath(options, lib)))) { + if (!options->qtDependencies[options->currentArchitecture].contains(QtDependency(lib, absoluteFilePath(options, lib)))) { ret = false; unmetDependencies->append(lib); } @@ -2027,25 +2014,22 @@ bool copyQtFiles(Options *options) QString libsDirectory = QLatin1String("libs/"); + // Copy other Qt dependencies - QString libDestinationDirectory = libsDirectory + options->architecture + QLatin1Char('/'); - QString assetsDestinationDirectory = QLatin1String("assets/--Added-by-androiddeployqt--/"); - for (const QtDependency &qtDependency : qAsConst(options->qtDependencies)) { + QString assetsDestinationDirectory = QStringLiteral("assets/--Added-by-androiddeployqt--/"); + for (const QtDependency &qtDependency : qAsConst(options->qtDependencies[options->currentArchitecture])) { QString sourceFileName = qtDependency.absolutePath; QString destinationFileName; - if (qtDependency.relativePath.endsWith(QLatin1String(".so"))) { + if (qtDependency.relativePath.endsWith(QStringLiteral(".so"))) { QString garbledFileName; - if (qtDependency.relativePath.startsWith(QLatin1String("lib/"))) { + if (qtDependency.relativePath.startsWith(QStringLiteral("lib/"))) { garbledFileName = qtDependency.relativePath.mid(sizeof("lib/") - 1); } else { - garbledFileName = QLatin1String("lib") - + QString(qtDependency.relativePath).replace(QLatin1Char('/'), QLatin1Char('_')); - + garbledFileName = QString(qtDependency.relativePath).replace(QLatin1Char('/'), QLatin1Char('_')); } - destinationFileName = libDestinationDirectory + garbledFileName; - - } else if (qtDependency.relativePath.startsWith(QLatin1String("jar/"))) { + destinationFileName = libsDirectory + options->currentArchitecture + QLatin1Char('/') + garbledFileName; + } else if (qtDependency.relativePath.startsWith(QStringLiteral("jar/"))) { destinationFileName = libsDirectory + qtDependency.relativePath.mid(sizeof("jar/") - 1); } else { destinationFileName = assetsDestinationDirectory + qtDependency.relativePath; @@ -2058,20 +2042,34 @@ bool copyQtFiles(Options *options) QStringList unmetDependencies; if (!goodToCopy(options, sourceFileName, &unmetDependencies)) { - fprintf(stdout, " -- Skipping %s. It has unmet dependencies: %s.\n", - qPrintable(sourceFileName), - qPrintable(unmetDependencies.join(QLatin1Char(',')))); + if (unmetDependencies.isEmpty()) { + if (options->verbose) { + fprintf(stdout, " -- Skipping %s, architecture mismatch.\n", + qPrintable(sourceFileName)); + } + } else { + if (unmetDependencies.isEmpty()) { + if (options->verbose) { + fprintf(stdout, " -- Skipping %s, architecture mismatch.\n", + qPrintable(sourceFileName)); + } + } else { + fprintf(stdout, " -- Skipping %s. It has unmet dependencies: %s.\n", + qPrintable(sourceFileName), + qPrintable(unmetDependencies.join(QLatin1Char(',')))); + } + } continue; } if (options->deploymentMechanism == Options::Bundled && !copyFileIfNewer(sourceFileName, options->outputDirectory + QLatin1Char('/') + destinationFileName, - options->verbose)) { + *options)) { return false; } - options->bundledFiles += qMakePair(destinationFileName, qtDependency.relativePath); + options->bundledFiles[options->currentArchitecture] += qMakePair(destinationFileName, qtDependency.relativePath); } return true; @@ -2409,21 +2407,18 @@ bool copyStdCpp(Options *options) if (options->verbose) fprintf(stdout, "Copying STL library\n"); - if (!QFile::exists(options->stdCppPath)) { - fprintf(stderr, "STL library does not exist at %s\n", qPrintable(options->stdCppPath)); - return false; - } - - const QString destinationDirectory = options->outputDirectory - + QLatin1String("/libs/") + options->architecture; - - if (!copyFileIfNewer(options->stdCppPath, destinationDirectory + QLatin1String("/lib") - + options->stdCppName + QLatin1String(".so"), - options->verbose)) { + QString stdCppPath = QStringLiteral("%1/%2/lib%3.so").arg(options->stdCppPath, options->architectures[options->currentArchitecture], options->stdCppName); + if (!QFile::exists(stdCppPath)) { + fprintf(stderr, "STL library does not exist at %s\n", qPrintable(stdCppPath)); + fflush(stdout); + fflush(stderr); return false; } - return true; + const QString destinationFile = QStringLiteral("%1/libs/%2/lib%3.so").arg(options->outputDirectory, + options->currentArchitecture, + options->stdCppName); + return copyFileIfNewer(stdCppPath, destinationFile, *options); } bool jarSignerSignPackage(const Options &options) @@ -2654,55 +2649,6 @@ bool signPackage(const Options &options) return apkSignerRunner() && QFile::remove(apkPath(options, UnsignedAPK)); } -bool copyGdbServer(const Options &options) -{ - if (options.verbose) - fprintf(stdout, "Copying gdbserver into package.\n"); - - QString architectureSubDirectory; - if (options.architecture == QLatin1String("arm64-v8a")) - architectureSubDirectory = QLatin1String("android-arm64"); - else if (options.architecture.startsWith(QLatin1String("arm"))) - architectureSubDirectory = QLatin1String("android-arm"); - else - architectureSubDirectory = QLatin1String("android-") + options.architecture; - - QString gdbServerBinary = options.ndkPath - + QLatin1String("/prebuilt/") - + architectureSubDirectory - + QLatin1String("/gdbserver/gdbserver"); - if (!QFile::exists(gdbServerBinary)) { - fprintf(stderr, "Cannot find gdbserver at %s.\n", qPrintable(gdbServerBinary)); - return false; - } - - QString gdbServerTarget = options.outputDirectory + QLatin1String("/libs/") + options.architecture; - - if (!copyFileIfNewer(gdbServerBinary, - gdbServerTarget + QLatin1String("/gdbserver"), - options.verbose) - || !copyFileIfNewer(gdbServerBinary, - gdbServerTarget + QLatin1String("/libgdbserver.so"), - options.verbose)) { - return false; - } - - QString addedByAndroidDeployQtPath = options.outputDirectory + QLatin1String("/assets/--Added-by-androiddeployqt--/"); - if (!QDir().mkpath(addedByAndroidDeployQtPath)) { - fprintf(stderr, "Failed to create directory '%s'", qPrintable(addedByAndroidDeployQtPath)); - return false; - } - QFile f(addedByAndroidDeployQtPath + QLatin1String("debugger.command")); - if (!f.open(QIODevice::WriteOnly)) { - fprintf(stderr, "Failed to create directory '%s'", qPrintable(addedByAndroidDeployQtPath)); - return false; - } - f.write("lib/libgdbserver.so --multi +"); - f.close(); - - return true; -} - bool generateAssetsFileList(const Options &options) { if (options.verbose) @@ -2764,8 +2710,6 @@ enum ErrorCode CannotCopyGnuStl = 5, CannotCopyQtFiles = 6, CannotFindApplicationBinary = 7, - CannotCopyGdbServer = 8, - CannotStripLibraries = 9, CannotCopyAndroidExtraLibs = 10, CannotCopyAndroidSources = 11, CannotUpdateAndroidFiles = 12, @@ -2813,25 +2757,7 @@ 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 (!copyAndroidExtraLibs(options)) - return CannotCopyAndroidExtraLibs; - if (!stripLibraries(options)) - return CannotStripLibraries; - if (!updateAndroidFiles(options)) - return CannotUpdateAndroidFiles; - if (options.generateAssetsFileList && !generateAssetsFileList(options)) - return CannotGenerateAssetsFileList; - return 0; - } - - if (options.build) { + if (options.build && !options.auxMode) { cleanAndroidFiles(options); if (Q_UNLIKELY(options.timing)) fprintf(stdout, "[TIMING] %d ms: Cleaned Android file\n", options.timer.elapsed()); @@ -2843,60 +2769,68 @@ int main(int argc, char *argv[]) fprintf(stdout, "[TIMING] %d ms: Copied Android template\n", options.timer.elapsed()); } - if (!readDependencies(&options)) - return CannotReadDependencies; - - if (Q_UNLIKELY(options.timing)) - fprintf(stdout, "[TIMING] %d ms: Read dependencies\n", options.timer.elapsed()); + for (auto it = options.architectures.constBegin(); it != options.architectures.constEnd(); ++it) { + options.clear(it.key()); - if (options.deploymentMechanism != Options::Ministro && !copyStdCpp(&options)) - return CannotCopyGnuStl; + if (!readDependencies(&options)) + return CannotReadDependencies; - if (Q_UNLIKELY(options.timing)) - fprintf(stdout, "[TIMING] %d ms: Copied GNU STL\n", options.timer.elapsed()); + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Read dependencies\n", options.timer.elapsed()); - if (!copyQtFiles(&options)) - return CannotCopyQtFiles; + if (!copyQtFiles(&options)) + return CannotCopyQtFiles; - if (options.build) { if (Q_UNLIKELY(options.timing)) fprintf(stdout, "[TIMING] %d ms: Copied Qt files\n", options.timer.elapsed()); - if (!containsApplicationBinary(options)) - return CannotFindApplicationBinary; + if (!copyAndroidExtraLibs(&options)) + return CannotCopyAndroidExtraLibs; if (Q_UNLIKELY(options.timing)) - fprintf(stdout, "[TIMING] %d ms: Checked for application binary\n", options.timer.elapsed()); + fprintf(stdout, "[TIMING] %d ms: Copied extra libs\n", options.timer.elapsed()); - bool needToCopyGdbServer = options.gdbServer == Options::True - || (options.gdbServer == Options::Auto && !options.releasePackage); - if (needToCopyGdbServer && !copyGdbServer(options)) - return CannotCopyGdbServer; + if (!copyAndroidExtraResources(&options)) + return CannotCopyAndroidExtraResources; if (Q_UNLIKELY(options.timing)) - fprintf(stdout, "[TIMING] %d ms: Copied GDB server\n", options.timer.elapsed()); + fprintf(stdout, "[TIMING] %d ms: Copied extra resources\n", options.timer.elapsed()); - if (!copyAndroidExtraLibs(options)) - return CannotCopyAndroidExtraLibs; + if (!options.auxMode) { + if (options.deploymentMechanism != Options::Ministro && !copyStdCpp(&options)) + return CannotCopyGnuStl; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Copied GNU STL\n", options.timer.elapsed()); + } + + if (!containsApplicationBinary(&options)) + return CannotFindApplicationBinary; if (Q_UNLIKELY(options.timing)) - fprintf(stdout, "[TIMING] %d ms: Copied extra libs\n", options.timer.elapsed()); + fprintf(stdout, "[TIMING] %d ms: Checked for application binary\n", options.timer.elapsed()); - if (!copyAndroidExtraResources(options)) - return CannotCopyAndroidExtraResources; + if (options.deploymentMechanism != Options::Ministro) { + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Bundled Qt libs\n", options.timer.elapsed()); + } + } + if (options.auxMode) { + if (!updateAndroidFiles(options)) + return CannotUpdateAndroidFiles; + if (options.generateAssetsFileList && !generateAssetsFileList(options)) + return CannotGenerateAssetsFileList; + return 0; + } + + if (options.build) { if (!copyAndroidSources(options)) return CannotCopyAndroidSources; if (Q_UNLIKELY(options.timing)) fprintf(stdout, "[TIMING] %d ms: Copied android sources\n", options.timer.elapsed()); - if (!stripLibraries(options)) - return CannotStripLibraries; - - if (Q_UNLIKELY(options.timing)) - fprintf(stdout, "[TIMING] %d ms: Stripped libraries\n", options.timer.elapsed()); - if (!updateAndroidFiles(options)) return CannotUpdateAndroidFiles; -- cgit v1.2.3