From 30e3a2beb1ba48bc4bc5de6d8188f9e8ebf8b5dc Mon Sep 17 00:00:00 2001 From: Dmitry Shachnev Date: Tue, 24 Feb 2015 19:05:04 +0300 Subject: [PATCH 01/10] Remove unneeded exec permission from icomoon fonts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I47f111b4fa1278889689c28da762fabe94b95015 Reviewed-by: Lisandro Damián Nicanor Pérez Meyer Reviewed-by: Topi Reiniö --- doc/global/template/style/icomoon.eot | Bin doc/global/template/style/icomoon.svg | 0 doc/global/template/style/icomoon.ttf | Bin doc/global/template/style/icomoon.woff | Bin 4 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 doc/global/template/style/icomoon.eot mode change 100755 => 100644 doc/global/template/style/icomoon.svg mode change 100755 => 100644 doc/global/template/style/icomoon.ttf mode change 100755 => 100644 doc/global/template/style/icomoon.woff diff --git a/doc/global/template/style/icomoon.eot b/doc/global/template/style/icomoon.eot old mode 100755 new mode 100644 diff --git a/doc/global/template/style/icomoon.svg b/doc/global/template/style/icomoon.svg old mode 100755 new mode 100644 diff --git a/doc/global/template/style/icomoon.ttf b/doc/global/template/style/icomoon.ttf old mode 100755 new mode 100644 diff --git a/doc/global/template/style/icomoon.woff b/doc/global/template/style/icomoon.woff old mode 100755 new mode 100644 From a9515cd02fabcb90691093c388be9849282a9e22 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 25 Feb 2015 10:53:31 +0100 Subject: [PATCH 02/10] doc: imagegestures example: document the pinch handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The swipe handler is simple, and also doesn't currently work on every platform. But the pinch handler is the one that needs explanation, because the difference between incremental and absolute values of the rotation and scale properties is tricky. Change-Id: Ie3c7f4941d4a17734c9a920a8dd978f86fb03c4b Reviewed-by: Friedemann Kleint Reviewed-by: Topi Reiniö --- .../imagegestures/doc/src/imagegestures.qdoc | 52 +++++++++++++++---- .../gestures/imagegestures/imagewidget.cpp | 13 +++-- 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/examples/widgets/gestures/imagegestures/doc/src/imagegestures.qdoc b/examples/widgets/gestures/imagegestures/doc/src/imagegestures.qdoc index 1b0406037c..07acef6b4d 100644 --- a/examples/widgets/gestures/imagegestures/doc/src/imagegestures.qdoc +++ b/examples/widgets/gestures/imagegestures/doc/src/imagegestures.qdoc @@ -83,18 +83,50 @@ QGesture subclass. To illustrate how a standard gesture can be interpreted by an application, we - show the implementation of the \c swipeTriggered() function, which handles the - gesture associated with a brushing or swiping motion on the user's display or + show the implementation of the \c pinchTriggered() function, which handles the + pinch gesture when the user moves two fingers around on the display or input device: - \snippet gestures/imagegestures/imagewidget.cpp swipe function + \snippet gestures/imagegestures/imagewidget.cpp pinch function - The QSwipeGesture class provides specialized functions and defines a enum - to make it more convenient for developers to discover which direction, if - any, the user swiped the display. Here, we simply navigate to the previous - image in the collection if the user swiped upwards or to the left; otherwise - we navigate to the next image in the collection. + The QPinchGesture class provides properties to interpret the changing + distance between the two touch points as a zoom factor, and the angle delta + as a rotation to be applied to the image. The center point between the + touch points could be used to drag the image, but in this example we use + the pan gesture for that purpose. - The other gestures are also handled by special purpose functions, but use - the values of properties held by the QGesture object passed to them. + The \c scaleFactor() is a relative value representing how much the zoom + should change from one event to the next, whereas \c totalScaleFactor() + provides the amount of zoom that has been expressed since the gesture + began. When the touch points are released and another gesture begins, + \c totalScaleFactor() will begin again at 1.0. In this case we store + \c totalScaleFactor() into the \c currentStepScaleFactor variable so that + it can be used in \c paintEvent() to scale the image. Alternatively it would + be possible to simply multiply the stored total scale factor by + \c scaleFactor() here in the pinch handler. + + In contrast, \c rotationAngle() represents the amount of rotation since the + pinch gesture began, while \c lastRotationAngle() provides the previous + value. So it is necessary to subtract in order to get an incremental delta. + When the user begins a new pinch gesture, \c rotationAngle() will start + from zero, and we want the image to begin to rotate from its current angle. + This is achieved by adding the delta to the stored \c rotationAngle (which + will be applied in \c paintEvent()). If we simply assigned + \c totalRotationAngle() to the stored \c rotationAngle, a new gesture would + cause the image to reset to a right-side-up orientation before beginning to + rotate again. But it would be possible to store the rotation angle since the + gesture began and add it to \c rotationAngle in \c paintEvent(), just as + we store the amount of zoom since the gesture began. + + The pan and swipe gestures in this example are also handled in separate + functions, and use the values of properties from the QGesture objects + passed to them. + + \snippet gestures/imagegestures/imagewidget.cpp paint method + + In \c paintEvent(), scaleFactor represents the zoom level before the pinch + gesture began, while currentStepScaleFactor represents the additional zoom + factor while a pinch gesture is in progress. But for rotation, only the + current rotationAngle is stored. The horizontal and vertical offsets + represent the distance that the image has been dragged by the pan gesture. */ diff --git a/examples/widgets/gestures/imagegestures/imagewidget.cpp b/examples/widgets/gestures/imagegestures/imagewidget.cpp index 38319a9dbe..3d0d7e7a93 100644 --- a/examples/widgets/gestures/imagegestures/imagewidget.cpp +++ b/examples/widgets/gestures/imagegestures/imagewidget.cpp @@ -77,6 +77,7 @@ bool ImageWidget::event(QEvent *event) } //! [event handler] +//! [paint method] void ImageWidget::paintEvent(QPaintEvent*) { QPainter p(this); @@ -93,6 +94,7 @@ void ImageWidget::paintEvent(QPaintEvent*) p.translate(-iw/2, -ih/2); p.drawImage(0, 0, currentImage); } +//! [paint method] void ImageWidget::mouseDoubleClickEvent(QMouseEvent *) { @@ -138,16 +140,20 @@ void ImageWidget::panTriggered(QPanGesture *gesture) update(); } +//! [pinch function] void ImageWidget::pinchTriggered(QPinchGesture *gesture) { QPinchGesture::ChangeFlags changeFlags = gesture->changeFlags(); if (changeFlags & QPinchGesture::RotationAngleChanged) { - rotationAngle += gesture->rotationAngle() - gesture->lastRotationAngle(); - qCDebug(lcExample) << "pinchTriggered(): rotate to" << rotationAngle; + qreal rotationDelta = gesture->rotationAngle() - gesture->lastRotationAngle(); + rotationAngle += rotationDelta; + qCDebug(lcExample) << "pinchTriggered(): rotate by" << + rotationDelta << "->" << rotationAngle; } if (changeFlags & QPinchGesture::ScaleFactorChanged) { currentStepScaleFactor = gesture->totalScaleFactor(); - qCDebug(lcExample) << "pinchTriggered(): zoom by" << gesture->scaleFactor() << "->" << currentStepScaleFactor; + qCDebug(lcExample) << "pinchTriggered(): zoom by" << + gesture->scaleFactor() << "->" << currentStepScaleFactor; } if (gesture->state() == Qt::GestureFinished) { scaleFactor *= currentStepScaleFactor; @@ -155,6 +161,7 @@ void ImageWidget::pinchTriggered(QPinchGesture *gesture) } update(); } +//! [pinch function] //! [swipe function] void ImageWidget::swipeTriggered(QSwipeGesture *gesture) From 34a58b0eb7c0c40be87e62251bc714d63293d51a Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 25 Feb 2015 15:32:07 +0100 Subject: [PATCH 03/10] avoid sending QPinchGestures based on unreasonable pinch deltas On some devices there can be spurious events indicating that the two touchpoints are very close together, so that the ratio of present line length to previous line length can be very large, and the angle delta can be random. But in the normal scenario, there will be a lot of events, in which the touch point movements are small. So if the line length ratio is unreasonable, it's safe to ignore one event and wait for the next. Task-number: QTBUG-44665 Change-Id: Ibb7fe560b6a3f7db72d73aad3468c61f24a95d13 Reviewed-by: Friedemann Kleint Reviewed-by: Laszlo Agocs --- src/widgets/kernel/qstandardgestures.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/widgets/kernel/qstandardgestures.cpp b/src/widgets/kernel/qstandardgestures.cpp index cf9ac52de3..d19e473d18 100644 --- a/src/widgets/kernel/qstandardgestures.cpp +++ b/src/widgets/kernel/qstandardgestures.cpp @@ -44,6 +44,11 @@ QT_BEGIN_NAMESPACE +// If the change in scale for a single touch event is out of this range, +// we consider it to be spurious. +static const qreal kSingleStepScaleMax = 2.0; +static const qreal kSingleStepScaleMin = 0.1; + QGesture *QPanGestureRecognizer::create(QObject *target) { if (target && target->isWidgetType()) { @@ -197,7 +202,10 @@ QGestureRecognizer::Result QPinchGestureRecognizer::recognize(QGesture *state, d->lastScaleFactor = d->scaleFactor; QLineF line(p1.screenPos(), p2.screenPos()); QLineF lastLine(p1.lastScreenPos(), p2.lastScreenPos()); - d->scaleFactor = line.length() / lastLine.length(); + qreal newScaleFactor = line.length() / lastLine.length(); + if (newScaleFactor > kSingleStepScaleMax || newScaleFactor < kSingleStepScaleMin) + return QGestureRecognizer::Ignore; + d->scaleFactor = newScaleFactor; } d->totalScaleFactor = d->totalScaleFactor * d->scaleFactor; d->changeFlags |= QPinchGesture::ScaleFactorChanged; From 877032bfdf0376cb5e438b3abe3fe5f45ce982c0 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 27 Feb 2015 10:22:36 +0100 Subject: [PATCH 04/10] autotests: fix the build in case of QT_NO_WHEELEVENT Wheel event tests aren't possible if there's no wheel event. Change-Id: Ibe380c01fbf6cebfd2f43c6ecb52863134ea3c01 Reviewed-by: Friedemann Kleint --- .../qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp | 6 ++++++ .../graphicsview/qgraphicsview/tst_qgraphicsview.cpp | 4 ++++ .../auto/widgets/itemviews/qtableview/tst_qtableview.cpp | 9 ++++++++- .../widgets/kernel/qapplication/tst_qapplication.cpp | 4 ++++ .../widgets/qabstractslider/tst_qabstractslider.cpp | 4 ++++ tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp | 4 ++++ .../widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp | 4 ++++ 7 files changed, 34 insertions(+), 1 deletion(-) diff --git a/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp b/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp index c1027dac18..f8d852888c 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp @@ -123,7 +123,9 @@ private slots: void resizeEvent_data(); void resizeEvent(); void paintEvent(); +#ifndef QT_NO_WHEELEVENT void wheelEvent(); +#endif void sizeHint_data(); void sizeHint(); void sizePolicy(); @@ -260,6 +262,7 @@ public: int focusOut; }; +#ifndef QT_NO_WHEELEVENT class WheelWidget : public QWidget { public: @@ -269,6 +272,7 @@ public: bool wheelEventCalled; }; +#endif // !QT_NO_WHEELEVENT // This will be called before the first test function is executed. // It is only called once. @@ -1308,6 +1312,7 @@ void tst_QGraphicsProxyWidget::paintEvent() } +#ifndef QT_NO_WHEELEVENT void tst_QGraphicsProxyWidget::wheelEvent() { QGraphicsScene scene; @@ -1331,6 +1336,7 @@ void tst_QGraphicsProxyWidget::wheelEvent() QVERIFY(event.isAccepted()); QVERIFY(wheelWidget->wheelEventCalled); } +#endif // !QT_NO_WHEELEVENT Q_DECLARE_METATYPE(Qt::SizeHint) void tst_QGraphicsProxyWidget::sizeHint_data() diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp index 783395fed4..119e9dfecb 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp @@ -198,7 +198,9 @@ private slots: void mapFromScenePoly(); void mapFromScenePath(); void sendEvent(); +#ifndef QT_NO_WHEELEVENT void wheelEvent(); +#endif #ifndef QTEST_NO_CURSOR void cursor(); void cursor2(); @@ -2172,6 +2174,7 @@ void tst_QGraphicsView::sendEvent() QCOMPARE(item->events.last(), QEvent::KeyPress); } +#ifndef QT_NO_WHEELEVENT class MouseWheelScene : public QGraphicsScene { public: @@ -2228,6 +2231,7 @@ void tst_QGraphicsView::wheelEvent() QCOMPARE(spy.count(), 2); QVERIFY(widget->hasFocus()); } +#endif // !QT_NO_WHEELEVENT #ifndef QTEST_NO_CURSOR void tst_QGraphicsView::cursor() diff --git a/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp b/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp index 4bea53c926..a11d423896 100644 --- a/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp +++ b/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp @@ -195,15 +195,19 @@ private slots: void task191545_dragSelectRows(); void taskQTBUG_5062_spansInconsistency(); void taskQTBUG_4516_clickOnRichTextLabel(); +#ifndef QT_NO_WHEELEVENT void taskQTBUG_5237_wheelEventOnHeader(); +#endif void taskQTBUG_8585_crashForNoGoodReason(); void taskQTBUG_7774_RtoLVisualRegionForSelection(); void taskQTBUG_8777_scrollToSpans(); void taskQTBUG_10169_sizeHintForRow(); void taskQTBUG_30653_doItemsLayout(); +#ifndef QT_NO_WHEELEVENT void mouseWheel_data(); void mouseWheel(); +#endif void addColumnWhileEditing(); void task234926_setHeaderSorting(); @@ -3994,7 +3998,7 @@ void tst_QTableView::task248688_autoScrollNavigation() } } - +#ifndef QT_NO_WHEELEVENT void tst_QTableView::mouseWheel_data() { QTest::addColumn("scrollMode"); @@ -4051,6 +4055,7 @@ void tst_QTableView::mouseWheel() QApplication::sendEvent(view.viewport(), &verticalEvent); QVERIFY(qAbs(view.verticalScrollBar()->value() - verticalPosition) < 10); } +#endif // !QT_NO_WHEELEVENT void tst_QTableView::addColumnWhileEditing() { @@ -4311,6 +4316,7 @@ void tst_QTableView::changeHeaderData() QVERIFY(view.verticalHeader()->width() > textWidth); } +#ifndef QT_NO_WHEELEVENT void tst_QTableView::taskQTBUG_5237_wheelEventOnHeader() { QTableView view; @@ -4327,6 +4333,7 @@ void tst_QTableView::taskQTBUG_5237_wheelEventOnHeader() int sbValueAfter = view.verticalScrollBar()->value(); QVERIFY(sbValueBefore != sbValueAfter); } +#endif class TestTableView : public QTableView { Q_OBJECT diff --git a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp index c3e8b51ccd..c9a1a64135 100644 --- a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp +++ b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp @@ -149,7 +149,9 @@ private slots: void execAfterExit(); +#ifndef QT_NO_WHEELEVENT void wheelScrollLines(); +#endif void task109149(); @@ -1844,6 +1846,7 @@ void tst_QApplication::execAfterExit() QCOMPARE(exitCode, 0); } +#ifndef QT_NO_WHEELEVENT void tst_QApplication::wheelScrollLines() { int argc = 1; @@ -1851,6 +1854,7 @@ void tst_QApplication::wheelScrollLines() // If wheelScrollLines returns 0, the mose wheel will be disabled. QVERIFY(app.wheelScrollLines() > 0); } +#endif // !QT_NO_WHEELEVENT void tst_QApplication::style() { diff --git a/tests/auto/widgets/widgets/qabstractslider/tst_qabstractslider.cpp b/tests/auto/widgets/widgets/qabstractslider/tst_qabstractslider.cpp index 7cb15fab3f..3c150e77b9 100644 --- a/tests/auto/widgets/widgets/qabstractslider/tst_qabstractslider.cpp +++ b/tests/auto/widgets/widgets/qabstractslider/tst_qabstractslider.cpp @@ -79,8 +79,10 @@ private slots: void minimum_maximum(); void keyPressed_data(); void keyPressed(); +#ifndef QT_NO_WHEELEVENT void wheelEvent_data(); void wheelEvent(); +#endif void sliderPressedReleased_data(); void sliderPressedReleased(); void setOrientation(); @@ -691,6 +693,7 @@ void tst_QAbstractSlider::keyPressed() QCOMPARE(slider->sliderPosition(), expectedSliderPositionVerticalInverted); } +#ifndef QT_NO_WHEELEVENT void tst_QAbstractSlider::wheelEvent_data() { QTest::addColumn("initialSliderPosition"); @@ -894,6 +897,7 @@ void tst_QAbstractSlider::wheelEvent() if (expectedSignalCount) QVERIFY(actionTriggeredTimeStamp < valueChangedTimeStamp); } +#endif // !QT_NO_WHEELEVENT void tst_QAbstractSlider::sliderPressedReleased_data() { diff --git a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp index 2a012f0dcd..7b4b65e841 100644 --- a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp +++ b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp @@ -122,9 +122,11 @@ private slots: void flaggedItems_data(); void flaggedItems(); void pixmapIcon(); +#ifndef QT_NO_WHEELEVENT void mouseWheel_data(); void mouseWheel(); void popupWheelHandling(); +#endif // !QT_NO_WHEELEVENT void layoutDirection(); void itemListPosition(); void separatorItem_data(); @@ -2004,6 +2006,7 @@ void tst_QComboBox::pixmapIcon() QCOMPARE( box.itemIcon(1).isNull(), false ); } +#ifndef QT_NO_WHEELEVENT // defined to be 120 by the wheel mouse vendors according to the docs #define WHEEL_DELTA 120 @@ -2094,6 +2097,7 @@ void tst_QComboBox::popupWheelHandling() QVERIFY(comboBox->view()->isVisible()); QCOMPARE(comboBox->view()->pos(), popupPos); } +#endif // !QT_NO_WHEELEVENT void tst_QComboBox::layoutDirection() { diff --git a/tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp b/tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp index 8f6d54e325..c9ae60dd76 100644 --- a/tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp +++ b/tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp @@ -236,7 +236,9 @@ private slots: void reverseTest(); void ddMMMMyyyy(); +#ifndef QT_NO_WHEELEVENT void wheelEvent(); +#endif void specialValueCornerCase(); void cursorPositionOnInit(); @@ -3028,6 +3030,7 @@ void tst_QDateTimeEdit::ddMMMMyyyy() QCOMPARE(testWidget->lineEdit()->text(), "01." + QDate::longMonthName(1) + ".200"); } +#ifndef QT_NO_WHEELEVENT void tst_QDateTimeEdit::wheelEvent() { testWidget->setDisplayFormat("dddd/MM"); @@ -3040,6 +3043,7 @@ void tst_QDateTimeEdit::wheelEvent() qApp->sendEvent(testWidget, &w); QCOMPARE(testWidget->date(), QDate(2000, 3, 22)); } +#endif // !QT_NO_WHEELEVENT void tst_QDateTimeEdit::specialValueCornerCase() { From 3b6d2575ae2662ae25b343adeb1f105ce8fd96d7 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 13 Jan 2015 15:54:15 +0100 Subject: [PATCH 05/10] QEvent types: use Q_ENUM qDebug support instead of custom formatters Change-Id: I10886de57b3ba24dddfcd4b78e1a32c470ac1889 Reviewed-by: Friedemann Kleint --- src/corelib/global/qnamespace.h | 1 + src/gui/kernel/qevent.cpp | 120 +++++--------------------------- 2 files changed, 19 insertions(+), 102 deletions(-) diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 2cde1bae81..e115cedc51 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -1680,6 +1680,7 @@ public: QT_Q_ENUM(InputMethodQuery) QT_Q_FLAG(InputMethodHints) QT_Q_FLAG(InputMethodQueries) + QT_Q_FLAG(TouchPointStates) QT_Q_ENUM(ScreenOrientation) QT_Q_FLAG(ScreenOrientations) QT_Q_ENUM(ConnectionType) diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index a0b5eb80bf..2995457180 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -3461,29 +3461,9 @@ QShortcutEvent::~QShortcutEvent() #ifndef QT_NO_DEBUG_STREAM -static inline void formatTouchPoint(QDebug d, const QTouchEvent::TouchPoint &tp) +static inline void formatTouchEvent(QDebug d, const QTouchEvent &t) { - d << "TouchPoint(" << tp.id() << ' ' << tp.rect(); - switch (tp.state()) { - case Qt::TouchPointPressed: - d << " pressed"; - break; - case Qt::TouchPointReleased: - d << " released"; - break; - case Qt::TouchPointMoved: - d << " moved"; - break; - case Qt::TouchPointStationary: - d << " stationary"; - break; - } - d << ')'; -} - -static inline void formatTouchEvent(QDebug d, const char *name, const QTouchEvent &t) -{ - d << "QTouchEvent(" << name << " states: " << t.touchPointStates(); + d << "QTouchEvent(" << t.type() << " states: " << t.touchPointStates(); d << ", " << t.touchPoints().size() << " points: " << t.touchPoints() << ')'; } @@ -3542,14 +3522,6 @@ static inline void formatInputMethodQueryEvent(QDebug d, const QInputMethodQuery d << "})"; } -static const char *eventTypeName(QEvent::Type t) -{ - static const int enumIdx = QEvent::staticMetaObject.indexOfEnumerator("Type"); - return t <= QEvent::User - ? QEvent::staticMetaObject.enumerator(enumIdx).valueToKey(t) - : "User"; -} - static const char *eventClassName(QEvent::Type t) { switch (t) { @@ -3667,54 +3639,6 @@ static const char *eventClassName(QEvent::Type t) return "QEvent"; } -namespace { -// Make protected QObject::staticQtMetaObject accessible for formatting enums. -class DebugHelper : public QObject { -public: - static const char *mouseButtonToString(Qt::MouseButton button) - { - static const int enumIdx = QObject::staticQtMetaObject.indexOfEnumerator("MouseButtons"); - return QObject::staticQtMetaObject.enumerator(enumIdx).valueToKey(button); - } - - static QByteArray mouseButtonsToString(Qt::MouseButtons buttons) - { - QByteArray result; - for (int i = 0; (uint)(1 << i) <= Qt::MaxMouseButton; ++i) { - const Qt::MouseButton button = static_cast(1 << i); - if (buttons.testFlag(button)) { - if (!result.isEmpty()) - result.append('|'); - result.append(mouseButtonToString(button)); - } - } - if (result.isEmpty()) - result.append("NoButton"); - return result; - } - - static const char *mouseEventSourceToString(Qt::MouseEventSource source) - { - static const int enumIdx = QObject::staticQtMetaObject.indexOfEnumerator("MouseEventSource"); - return QObject::staticQtMetaObject.enumerator(enumIdx).valueToKey(source); - } - - static const char *focusReasonToString(Qt::FocusReason reason) - { - static const int enumIdx = QObject::staticQtMetaObject.indexOfEnumerator("FocusReason"); - return QObject::staticQtMetaObject.enumerator(enumIdx).valueToKey(reason); - } - -# ifndef QT_NO_GESTURES - static const char *nativeGestureTypeToString(Qt::NativeGestureType type) - { - static const int enumIdx = QObject::staticQtMetaObject.indexOfEnumerator("NativeGestureType"); - return QObject::staticQtMetaObject.enumerator(enumIdx).valueToKey(type); - } -# endif // !QT_NO_GESTURES -}; -} // namespace - # ifndef QT_NO_DRAGANDDROP static void formatDropEvent(QDebug d, const QDropEvent *e) @@ -3728,7 +3652,7 @@ static void formatDropEvent(QDebug d, const QDropEvent *e) d << ", formats=" << e->mimeData()->formats(); if (const Qt::KeyboardModifiers mods = e->keyboardModifiers()) d << ", keyboardModifiers=" << mods; - d << ", " << DebugHelper::mouseButtonsToString(e->mouseButtons()).constData(); + d << ", " << e->mouseButtons(); } # endif // !QT_NO_DRAGANDDROP @@ -3739,20 +3663,15 @@ static void formatTabletEvent(QDebug d, const QTabletEvent *e) { const QEvent::Type type = e->type(); - static const int deviceEnumIdx = QTabletEvent::staticMetaObject.indexOfEnumerator("TabletDevice"); - static const int pointerTypeEnumIdx = QTabletEvent::staticMetaObject.indexOfEnumerator("PointerType"); - const char* device = QTabletEvent::staticMetaObject.enumerator(deviceEnumIdx).valueToKey(e->device()); - const char* pointerType = QTabletEvent::staticMetaObject.enumerator(pointerTypeEnumIdx).valueToKey(e->pointerType()); - - d << eventClassName(type) << '(' << eventTypeName(type) - << ", device=" << device - << ", pointerType=" << pointerType + d << eventClassName(type) << '(' << type + << ", device=" << e->device() + << ", pointerType=" << e->pointerType() << ", uniqueId=" << e->uniqueId() << ", pos=" << e->posF() << ", z=" << e->z() << ", xTilt=" << e->xTilt() << ", yTilt=" << e->yTilt() - << ", " << DebugHelper::mouseButtonsToString(e->buttons()).constData(); + << ", " << e->buttons(); if (type == QEvent::TabletPress || type == QEvent::TabletMove) d << ", pressure=" << e->pressure(); if (e->device() == QTabletEvent::RotationStylus || e->device() == QTabletEvent::FourDMouse) @@ -3766,8 +3685,7 @@ static void formatTabletEvent(QDebug d, const QTabletEvent *e) QDebug operator<<(QDebug dbg, const QTouchEvent::TouchPoint &tp) { QDebugStateSaver saver(dbg); - dbg.nospace(); - formatTouchPoint(dbg, tp); + dbg.nospace() << "TouchPoint(" << tp.id() << ' ' << tp.rect() << ' ' << tp.state() << " vel " << tp.velocity() << ')'; return dbg; } @@ -3797,16 +3715,16 @@ QDebug operator<<(QDebug dbg, const QEvent *e) const QMouseEvent *me = static_cast(e); const Qt::MouseButton button = me->button(); const Qt::MouseButtons buttons = me->buttons(); - dbg << "QMouseEvent(" << eventTypeName(type); + dbg << "QMouseEvent(" << type; if (type != QEvent::MouseMove && type != QEvent::NonClientAreaMouseMove) - dbg << ", " << DebugHelper::mouseButtonToString(button); + dbg << ", " << button; if (buttons && button != buttons) - dbg << ", buttons=" << DebugHelper::mouseButtonsToString(buttons).constData(); + dbg << ", buttons=" << buttons; if (const int mods = int(me->modifiers())) dbg << ", modifiers=0x" << hex << mods << dec; dbg << ", localPos=" << me->localPos() << ", screenPos=" << me->screenPos(); if (me->source()) - dbg << ", " << DebugHelper::mouseEventSourceToString(me->source()); + dbg << ", " << me->source(); if (const Qt::MouseEventFlags flags = me->flags()) dbg << ", flags = " << hex << int(flags) << dec; dbg << ')'; @@ -3824,7 +3742,7 @@ QDebug operator<<(QDebug dbg, const QEvent *e) case QEvent::ShortcutOverride: { const QKeyEvent *ke = static_cast(e); - dbg << "QKeyEvent(" << eventTypeName(type) + dbg << "QKeyEvent(" << type << ", key=0x" << hex << ke->key() << dec; if (const int mods = ke->modifiers()) dbg << ", modifiers=0x" << hex << mods << dec; @@ -3846,9 +3764,7 @@ QDebug operator<<(QDebug dbg, const QEvent *e) case QEvent::FocusAboutToChange: case QEvent::FocusIn: case QEvent::FocusOut: - dbg << "QFocusEvent(" << eventTypeName(type) << ", " - << DebugHelper::focusReasonToString(static_cast(e)->reason()) - << ')'; + dbg << "QFocusEvent(" << type << ", " << static_cast(e)->reason() << ')'; break; case QEvent::Move: { const QMoveEvent *me = static_cast(e); @@ -3882,17 +3798,17 @@ QDebug operator<<(QDebug dbg, const QEvent *e) case QEvent::TouchBegin: case QEvent::TouchUpdate: case QEvent::TouchEnd: - formatTouchEvent(dbg, eventTypeName(type), *static_cast(e)); + formatTouchEvent(dbg, *static_cast(e)); break; case QEvent::ChildAdded: case QEvent::ChildPolished: case QEvent::ChildRemoved: - dbg << "QChildEvent(" << eventTypeName(type) << ", " << (static_cast(e))->child() << ')'; + dbg << "QChildEvent(" << type << ", " << (static_cast(e))->child() << ')'; break; # ifndef QT_NO_GESTURES case QEvent::NativeGesture: { const QNativeGestureEvent *ne = static_cast(e); - dbg << "QNativeGestureEvent(" << DebugHelper::nativeGestureTypeToString(ne->gestureType()) + dbg << "QNativeGestureEvent(" << ne->gestureType() << "localPos=" << ne->localPos() << ", value=" << ne->value() << ')'; } break; @@ -3932,7 +3848,7 @@ QDebug operator<<(QDebug dbg, const QEvent *e) dbg << ')'; break; default: - dbg << eventClassName(type) << '(' << eventTypeName(type) << ", " + dbg << eventClassName(type) << '(' << type << ", " << (const void *)e << ", type = " << e->type() << ')'; break; } From b13432747578cb3a1121b8cf9e870396b0bb53c2 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 27 Feb 2015 14:56:55 +0100 Subject: [PATCH 06/10] QTabletEvent manual test: use built-in QDebug operator There's no need to decode the event details here anymore, and anyway this had a bug: it always said the device is unknown. Change-Id: If99dddbe2136d95e818f4fe526f62650cbd7c1ca Reviewed-by: Friedemann Kleint --- .../qtabletevent/regular_widgets/main.cpp | 88 +++---------------- 1 file changed, 11 insertions(+), 77 deletions(-) diff --git a/tests/manual/qtabletevent/regular_widgets/main.cpp b/tests/manual/qtabletevent/regular_widgets/main.cpp index 2ac57986b3..5a83decfa2 100644 --- a/tests/manual/qtabletevent/regular_widgets/main.cpp +++ b/tests/manual/qtabletevent/regular_widgets/main.cpp @@ -147,29 +147,23 @@ void EventReportWidget::paintEvent(QPaintEvent *) void EventReportWidget::tabletEvent(QTabletEvent *event) { - QWidget::tabletEvent(event); - QString type; + bool isMove = false; switch (event->type()) { case QEvent::TabletEnterProximity: - type = QString::fromLatin1("TabletEnterProximity"); - break; case QEvent::TabletLeaveProximity: - type = QString::fromLatin1("TabletLeaveProximity"); break; case QEvent::TabletMove: - type = QString::fromLatin1("TabletMove"); m_points.push_back(TabletPoint(event->pos(), TabletMove, m_lastButton, event->pointerType(), event->pressure(), event->rotation())); update(); + isMove = true; break; case QEvent::TabletPress: - type = QString::fromLatin1("TabletPress"); m_points.push_back(TabletPoint(event->pos(), TabletButtonPress, event->button(), event->pointerType(), event->rotation())); m_lastButton = event->button(); update(); break; case QEvent::TabletRelease: - type = QString::fromLatin1("TabletRelease"); m_points.push_back(TabletPoint(event->pos(), TabletButtonRelease, event->button(), event->pointerType(), event->rotation())); update(); break; @@ -178,84 +172,24 @@ void EventReportWidget::tabletEvent(QTabletEvent *event) break; } - QString pointerType = "UNKNOWN"; - switch (event->pointerType()) { - case QTabletEvent::Pen: - pointerType = "Pen"; - break; - case QTabletEvent::Cursor: - pointerType = "Cursor"; - break; - case QTabletEvent::Eraser: - pointerType = "Eraser"; - break; - default: - break; + if (!(isMove && m_lastIsTabletMove)) { + QDebug d = qDebug(); + d << event << " global position = " << event->globalPos() + << " cursor at " << QCursor::pos(); + if (event->button() != Qt::NoButton) + d << " changed button " << event->button(); } - - QString device = "UNKNOWN"; - switch (event->device()) { - case QTabletEvent::Puck: - pointerType = "Puck"; - break; - case QTabletEvent::Stylus: - pointerType = "Stylus"; - break; - case QTabletEvent::Airbrush: - pointerType = "Airbrush"; - break; - case QTabletEvent::FourDMouse: - pointerType = "FourDMouse"; - break; - case QTabletEvent::RotationStylus: - pointerType = "RotationStylus"; - break; - default: - break; - } - - if (!m_lastIsTabletMove) - qDebug() << "Tablet event, type = " << type - << " position = " << event->pos() - << " global position = " << event->globalPos() - << " cursor at " << QCursor::pos() - << " buttons " << event->buttons() << " changed " << event->button() - << " pointer type " << pointerType << " device " << device; - - m_lastIsTabletMove = (event->type() == QEvent::TabletMove); + m_lastIsTabletMove = isMove; } void EventReportWidget::outputMouseEvent(QMouseEvent *event) { - QString type; - switch (event->type()) { - case QEvent::MouseButtonDblClick: - m_lastIsMouseMove = false; - type = QString::fromLatin1("MouseButtonDblClick"); - break; - case QEvent::MouseButtonPress: - m_lastIsMouseMove = false; - type = QString::fromLatin1("MouseButtonPress"); - break; - case QEvent::MouseButtonRelease: - m_lastIsMouseMove = false; - type = QString::fromLatin1("MouseButtonRelease"); - break; - case QEvent::MouseMove: + if (event->type() == QEvent::MouseMove) { if (m_lastIsMouseMove) return; // only show one move to keep things readable - m_lastIsMouseMove = true; - type = QString::fromLatin1("MouseMove"); - break; - default: - Q_ASSERT(false); - break; } - - qDebug() << "Mouse event, type = " << type - << " position = " << event->pos() - << " global position = " << event->globalPos(); + qDebug() << event; } int main(int argc, char *argv[]) From bfb92c03e0d8e7a3a65b64d1f2f5b89f442e2b8a Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Sun, 10 Aug 2014 19:23:35 +0200 Subject: [PATCH 07/10] Document Q_ENUM and Q_FLAG [ChangeLog][QtCore] Q_ENUMS and Q_FLAGS have been deprecated, and replaced by Q_ENUM and Q_FLAG macros. These two new macros automatically register the enum with the Qt metatype system, allowing automatic conversion to or from string in QVariant, or to show the strings by QDebug operators. They also enable the new QMetaEnum::fromType function. Change-Id: I80cccd7ad3fc46b11aee2fe50681a8126debf972 Reviewed-by: Marc Mutz Reviewed-by: Shawn Rutledge --- .../doc/snippets/code/doc_src_properties.cpp | 2 +- .../code/src_corelib_kernel_qobject.cpp | 17 ++--- .../doc/src/objectmodel/properties.qdoc | 10 +-- src/corelib/kernel/qobject.cpp | 75 ++++++++++++++++--- 4 files changed, 78 insertions(+), 26 deletions(-) diff --git a/src/corelib/doc/snippets/code/doc_src_properties.cpp b/src/corelib/doc/snippets/code/doc_src_properties.cpp index d07c7cb947..8978d1a067 100644 --- a/src/corelib/doc/snippets/code/doc_src_properties.cpp +++ b/src/corelib/doc/snippets/code/doc_src_properties.cpp @@ -93,13 +93,13 @@ class MyClass : public QObject { Q_OBJECT Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged) - Q_ENUMS(Priority) public: MyClass(QObject *parent = 0); ~MyClass(); enum Priority { High, Low, VeryHigh, VeryLow }; + Q_ENUM(Priority) void setPriority(Priority priority) { diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp index 0bf67fce31..b0048014a4 100644 --- a/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp @@ -376,38 +376,37 @@ Q_PROPERTY(QString title READ title WRITE setTitle USER true) class MyClass : public QObject { Q_OBJECT - Q_ENUMS(Priority) public: MyClass(QObject *parent = 0); ~MyClass(); enum Priority { High, Low, VeryHigh, VeryLow }; + Q_ENUM(Priority) void setPriority(Priority priority); Priority priority() const; }; //! [38] -//! [39a] +//! [39] class QLibrary : public QObject { - ... - Q_FLAGS(LoadHint LoadHints) - ... -//! [39a] + Q_OBJECT -//! [39b] - ... public: + ... + enum LoadHint { ResolveAllSymbolsHint = 0x01, ExportExternalSymbolsHint = 0x02, LoadArchiveMemberHint = 0x04 }; Q_DECLARE_FLAGS(LoadHints, LoadHint) + Q_FLAG(LoadHints) ... -//! [39b] +} +//! [39] //! [40] diff --git a/src/corelib/doc/src/objectmodel/properties.qdoc b/src/corelib/doc/src/objectmodel/properties.qdoc index 5db1410e6f..abb0720fe9 100644 --- a/src/corelib/doc/src/objectmodel/properties.qdoc +++ b/src/corelib/doc/src/objectmodel/properties.qdoc @@ -207,7 +207,7 @@ section of the class. The required \c READ function is named \c priority, and we include a \c WRITE function named \c setPriority. The enumeration type must be registered with the \l {Meta-Object - System} using the Q_ENUMS() macro. Registering an enumeration type + System} using the Q_ENUM() macro. Registering an enumeration type makes the enumerator names available for use in calls to QObject::setProperty(). We must also provide our own declarations for the \c READ and \c WRITE functions. The declaration of MyClass @@ -228,18 +228,18 @@ In the example, the enumeration type that is the property type is declared in MyClass and registered with the \l{Meta-Object System} - using the Q_ENUMS() macro. This makes the enumeration values + using the Q_ENUM() macro. This makes the enumeration values available as strings for use as in the call to \l{QObject::}{setProperty()}. Had the enumeration type been declared in another class, its fully qualified name (i.e., OtherClass::Priority) would be required, and that other class would also have to inherit QObject and register - the enumeration type there using the Q_ENUMS() macro. + the enumeration type there using the Q_ENUM() macro. - A similar macro, Q_FLAGS(), is also available. Like Q_ENUMS(), it + A similar macro, Q_FLAG(), is also available. Like Q_ENUM(), it registers an enumeration type, but it marks the type as being a set of \e flags, i.e. values that can be OR'd together. An I/O class might have enumeration values \c Read and \c Write and then - QObject::setProperty() could accept \c{Read | Write}. Q_FLAGS() + QObject::setProperty() could accept \c{Read | Write}. Q_FLAG() should be used to register this enumeration type. \section1 Dynamic Properties diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 265cc68db5..40279cf2b3 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -4178,6 +4178,7 @@ QDebug operator<<(QDebug dbg, const QObject *o) /*! \macro Q_ENUMS(...) \relates QObject + \obsolete This macro registers one or several enum types to the meta-object system. @@ -4191,35 +4192,87 @@ QDebug operator<<(QDebug dbg, const QObject *o) defining it. In addition, the class \e defining the enum has to inherit QObject as well as declare the enum using Q_ENUMS(). + In new code, you should prefer the use of the Q_ENUM() macro, which makes the + type available also to the meta type system. + For instance, QMetaEnum::fromType() will not work with types declared with Q_ENUMS(). + \sa {Qt's Property System} */ /*! \macro Q_FLAGS(...) \relates QObject + \obsolete - This macro registers one or several \l{QFlags}{flags types} to the + This macro registers one or several \l{QFlags}{flags types} with the meta-object system. It is typically used in a class definition to declare that values of a given enum can be used as flags and combined using the bitwise OR operator. - For example, in QLibrary, the \l{QLibrary::LoadHints}{LoadHints} flag is - declared in the following way: - - \snippet code/src_corelib_kernel_qobject.cpp 39a - - The declaration of the flags themselves is performed in the public section - of the QLibrary class itself, using the \l Q_DECLARE_FLAGS() macro: - - \snippet code/src_corelib_kernel_qobject.cpp 39b - \note This macro takes care of registering individual flag values with the meta-object system, so it is unnecessary to use Q_ENUMS() in addition to this macro. + In new code, you should prefer the use of the Q_FLAG() macro, which makes the + type available also to the meta type system. + \sa {Qt's Property System} */ +/*! + \macro Q_ENUM(...) + \relates QObject + \since 5.5 + + This macro registers an enum type with the meta-object system. + It must be placed after the enum declaration in a class that has the Q_OBJECT or the + Q_GADGET macro. + + For example: + + \snippet code/src_corelib_kernel_qobject.cpp 38 + + Enumerations that are declared with Q_ENUM have their QMetaEnum registered in the + enclosing QMetaObject. You can also use QMetaEnum::fromType() to get the QMetaEnum. + + Registered enumerations are automatically registered also to the Qt meta + type system, making them known to QMetaType without the need to use + Q_DECLARE_METATYPE(). This will enable useful features; for example, if used + in a QVariant, you can convert them to strings. Likewise, passing them to + QDebug will print out their names. + + \sa {Qt's Property System} +*/ + + +/*! + \macro Q_FLAG(...) + \relates QObject + \since 5.5 + + This macro registers a single \l{QFlags}{flags types} with the + meta-object system. It is typically used in a class definition to declare + that values of a given enum can be used as flags and combined using the + bitwise OR operator. + + The macro must be placed after the enum declaration. + + For example, in QLibrary, the \l{QLibrary::LoadHints}{LoadHints} flag is + declared in the following way: + + \snippet code/src_corelib_kernel_qobject.cpp 39 + + The declaration of the flags themselves is performed in the public section + of the QLibrary class itself, using the \l Q_DECLARE_FLAGS() macro. + + \note The Q_FLAG macro takes care of registering individual flag values + with the meta-object system, so it is unnecessary to use Q_ENUM() + in addition to this macro. + + \sa {Qt's Property System} +*/ + + /*! \macro Q_OBJECT \relates QObject From 59f168c5e5eec7ac247e6154a65f85a7ccc6e7ad Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 19 Feb 2015 11:20:52 +0100 Subject: [PATCH 08/10] Optimize fallback RGB888 to RGB32 conversion Improves the conversion from RGB888 to RGB32 on platforms without SIMD versions. This includes the fallback used on non-neon ARM devices. Besides image conversion the routine is also used for decoding JPEG. On x86 this version is within 0.7x of the speed of the SSSE3 version. Change-Id: Id131994d7c3c4f879d89e80f9d6c435bb5535ed7 Reviewed-by: Gunnar Sletta --- src/gui/image/qimage_conversions.cpp | 117 ++++++++++++++++-- src/gui/image/qjpeghandler.cpp | 18 +-- tests/auto/gui/image/qimage/tst_qimage.cpp | 7 ++ .../qimageconversion/tst_qimageconversion.cpp | 24 +++- 4 files changed, 143 insertions(+), 23 deletions(-) diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index a4c02bbbbe..5103d820d6 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -35,8 +35,8 @@ #include #include #include - #include +#include QT_BEGIN_NAMESPACE @@ -290,6 +290,108 @@ static void convert_ARGB_to_ARGB_PM_sse4(QImageData *dest, const QImageData *src } #endif +Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32(quint32 *dest_data, const uchar *src_data, int len) +{ + int pixel = 0; + // prolog: align input to 32bit + while ((quintptr(src_data) & 0x3) && pixel < len) { + *dest_data = 0xff000000 | (src_data[0] << 16) | (src_data[1] << 8) | (src_data[2]); + src_data += 3; + ++dest_data; + ++pixel; + } + + // Handle 4 pixels at a time 12 bytes input to 16 bytes output. + for (; pixel + 3 < len; pixel += 4) { + const quint32 *src_packed = (quint32 *) src_data; + const quint32 src1 = qFromBigEndian(src_packed[0]); + const quint32 src2 = qFromBigEndian(src_packed[1]); + const quint32 src3 = qFromBigEndian(src_packed[2]); + + dest_data[0] = 0xff000000 | (src1 >> 8); + dest_data[1] = 0xff000000 | (src1 << 16) | (src2 >> 16); + dest_data[2] = 0xff000000 | (src2 << 8) | (src3 >> 24); + dest_data[3] = 0xff000000 | src3; + + src_data += 12; + dest_data += 4; + } + + // epilog: handle left over pixels + for (; pixel < len; ++pixel) { + *dest_data = 0xff000000 | (src_data[0] << 16) | (src_data[1] << 8) | (src_data[2]); + src_data += 3; + ++dest_data; + } +} + +Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgbx8888(quint32 *dest_data, const uchar *src_data, int len) +{ + int pixel = 0; + // prolog: align input to 32bit + while ((quintptr(src_data) & 0x3) && pixel < len) { + *dest_data = ARGB2RGBA(0xff000000 | (src_data[0] << 16) | (src_data[1] << 8) | (src_data[2])); + src_data += 3; + ++dest_data; + ++pixel; + } + + // Handle 4 pixels at a time 12 bytes input to 16 bytes output. + for (; pixel + 3 < len; pixel += 4) { + const quint32 *src_packed = (quint32 *) src_data; + const quint32 src1 = src_packed[0]; + const quint32 src2 = src_packed[1]; + const quint32 src3 = src_packed[2]; + +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + dest_data[0] = 0xff000000 | src1; + dest_data[1] = 0xff000000 | (src1 >> 24) | (src2 << 8); + dest_data[2] = 0xff000000 | (src2 >> 16) | (src3 << 16); + dest_data[3] = 0xff000000 | (src3 >> 8); +#else + dest_data[0] = 0xff | src1; + dest_data[1] = 0xff | (src1 << 24) | (src2 >> 8); + dest_data[2] = 0xff | (src2 << 16) | (src3 >> 16); + dest_data[3] = 0xff | (src3 << 8); +#endif + + src_data += 12; + dest_data += 4; + } + + // epilog: handle left over pixels + for (; pixel < len; ++pixel) { + *dest_data = ARGB2RGBA(0xff000000 | (src_data[0] << 16) | (src_data[1] << 8) | (src_data[2])); + src_data += 3; + ++dest_data; + } +} + +typedef void (QT_FASTCALL *Rgb888ToRgbConverter)(quint32 *dst, const uchar *src, int len); + +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(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); + + const uchar *src_data = (uchar *) src->data; + quint32 *dest_data = (quint32 *) dest->data; + + Rgb888ToRgbConverter line_converter= rgbx ? qt_convert_rgb888_to_rgbx8888 : qt_convert_rgb888_to_rgb32; + + for (int i = 0; i < src->height; ++i) { + line_converter(dest_data, src_data, src->width); + src_data += src->bytes_per_line; + dest_data = (quint32 *)((uchar*)dest_data + dest->bytes_per_line); + } +} + extern bool convert_ARGB_to_ARGB_PM_inplace_sse2(QImageData *data, Qt::ImageConversionFlags); static void convert_ARGB_to_RGBx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) @@ -2052,6 +2154,9 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, + convert_RGB888_to_RGB, + convert_RGB888_to_RGB, + convert_RGB888_to_RGB, 0, 0, 0, @@ -2061,12 +2166,10 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, - 0, - 0, - 0, - 0, - 0, 0, 0, 0, 0, 0, 0 + convert_RGB888_to_RGB, + convert_RGB888_to_RGB, + convert_RGB888_to_RGB, + 0, 0, 0, 0, 0, 0 }, // Format_RGB888 { diff --git a/src/gui/image/qjpeghandler.cpp b/src/gui/image/qjpeghandler.cpp index 13ac59ec26..b1146c4297 100644 --- a/src/gui/image/qjpeghandler.cpp +++ b/src/gui/image/qjpeghandler.cpp @@ -69,18 +69,10 @@ extern "C" { QT_BEGIN_NAMESPACE -void QT_FASTCALL convert_rgb888_to_rgb32_C(quint32 *dst, const uchar *src, int len) -{ - // Expand 24->32 bpp. - for (int i = 0; i < len; ++i) { - *dst++ = qRgb(src[0], src[1], src[2]); - src += 3; - } -} - +Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32(quint32 *dst, const uchar *src, int len); typedef void (QT_FASTCALL *Rgb888ToRgb32Converter)(quint32 *dst, const uchar *src, int len); -static Rgb888ToRgb32Converter rgb888ToRgb32ConverterPtr = convert_rgb888_to_rgb32_C; +static Rgb888ToRgb32Converter rgb888ToRgb32ConverterPtr = qt_convert_rgb888_to_rgb32; struct my_error_mgr : public jpeg_error_mgr { jmp_buf setjmp_buffer; @@ -1008,10 +1000,8 @@ QJpegHandler::QJpegHandler() #endif #if defined(QT_COMPILER_SUPPORTS_SSSE3) - // from qimage_ssse3.cpp - - if (false) { - } else if (qCpuHasFeature(SSSE3)) { + // from qimage_ssse3.cpps + if (qCpuHasFeature(SSSE3)) { rgb888ToRgb32ConverterPtr = qt_convert_rgb888_to_rgb32_ssse3; } #endif // QT_COMPILER_SUPPORTS_SSSE3 diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp index 7d2d009213..decd4ef931 100644 --- a/tests/auto/gui/image/qimage/tst_qimage.cpp +++ b/tests/auto/gui/image/qimage/tst_qimage.cpp @@ -734,6 +734,13 @@ void tst_QImage::convertToFormat_data() QTest::newRow("blue rgb888 -> 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 + << int(QImage::Format_RGBX8888) << 0xff00ff00; + QTest::newRow("blue rgb888 -> rgbx8888") << int(QImage::Format_RGB888) << 0xff0000ff + << int(QImage::Format_RGBX8888) << 0xff0000ff; + QTest::newRow("semired argb32 -> rgb888") << int(QImage::Format_ARGB32) << 0x7fff0000u << int(QImage::Format_RGB888) << 0xffff0000; QTest::newRow("semigreen argb32 -> rgb888") << int(QImage::Format_ARGB32) << 0x7f00ff00u diff --git a/tests/benchmarks/gui/image/qimageconversion/tst_qimageconversion.cpp b/tests/benchmarks/gui/image/qimageconversion/tst_qimageconversion.cpp index d4834a04e2..2d4a453b58 100644 --- a/tests/benchmarks/gui/image/qimageconversion/tst_qimageconversion.cpp +++ b/tests/benchmarks/gui/image/qimageconversion/tst_qimageconversion.cpp @@ -43,6 +43,9 @@ private slots: void convertRgb888ToRgb32_data(); void convertRgb888ToRgb32(); + void convertRgb888ToRgbx8888_data(); + void convertRgb888ToRgbx8888(); + void convertRgb32ToRgb888_data(); void convertRgb32ToRgb888(); @@ -74,8 +77,8 @@ void tst_QImageConversion::convertRgb888ToRgb32_data() // 16 pixels, minimum for the SSSE3 implementation QTest::newRow("width: 16px; height: 5000px;") << generateImageRgb888(16, 5000); - // 50 pixels, more realistic use case - QTest::newRow("width: 50px; height: 5000px;") << generateImageRgb888(50, 5000); + // 200 pixels, more realistic use case + QTest::newRow("width: 200px; height: 5000px;") << generateImageRgb888(200, 5000); // 2000 pixels -> typical values for pictures QTest::newRow("width: 2000px; height: 2000px;") << generateImageRgb888(2000, 2000); @@ -93,6 +96,23 @@ void tst_QImageConversion::convertRgb888ToRgb32() } } +void tst_QImageConversion::convertRgb888ToRgbx8888_data() +{ + convertRgb888ToRgb32_data(); +} + +void tst_QImageConversion::convertRgb888ToRgbx8888() +{ + QFETCH(QImage, inputImage); + + QBENCHMARK { + volatile QImage output = inputImage.convertToFormat(QImage::Format_RGBX8888); + // we need the volatile and the following to make sure the compiler does not do + // anything stupid :) + (void)output; + } +} + void tst_QImageConversion::convertRgb32ToRgb888_data() { QTest::addColumn("inputImage"); From 96e9b41e254aaeff2e1bb320791fa6e19f179e2b Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 3 Mar 2015 16:31:52 -0800 Subject: [PATCH 09/10] tst_QNetworkDiskCache: Stop using actual web servers www.example.com is a reserved domain (RFC 6761), but IANA is running a web server there. As for www.foo.com, that also exists, is a real website and is often content-filtered in corporations (it triggers a firewall warning for me -- "You attempted to visit a site that is in violation of Intel acceptable use guidelines"). So use a localhost instead, since we don't actually need to connect to the servers to do the work. And since we don't need to connect, I chose port 4 as it's extremely unlikely someone is running an HTTP server there (/etc/services lists it as unassigned). Change-Id: Ia0aac2f09e9245339951ffff13c82439c6d5f945 Reviewed-by: Lars Knoll Reviewed-by: Oswald Buddenhagen --- .../access/qnetworkdiskcache/tst_qnetworkdiskcache.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/auto/network/access/qnetworkdiskcache/tst_qnetworkdiskcache.cpp b/tests/auto/network/access/qnetworkdiskcache/tst_qnetworkdiskcache.cpp index a2f1668ef5..8eee4bdbb3 100644 --- a/tests/auto/network/access/qnetworkdiskcache/tst_qnetworkdiskcache.cpp +++ b/tests/auto/network/access/qnetworkdiskcache/tst_qnetworkdiskcache.cpp @@ -38,7 +38,7 @@ #include -#define EXAMPLE_URL "http://user:pass@www.example.com/#foo" +#define EXAMPLE_URL "http://user:pass@localhost:4/#foo" //cached objects are organized into these many subdirs #define NUM_SUBDIRECTORIES 16 @@ -409,7 +409,7 @@ void tst_QNetworkDiskCache::accessAfterRemoveReadyReadSlot() void tst_QNetworkDiskCache::setCookieHeader() // QTBUG-41514 { SubQNetworkDiskCache *cache = new SubQNetworkDiskCache(); - url = QUrl("http://www.foo.com/cookieTest.html"); + url = QUrl("http://localhost:4/cookieTest.html"); // hopefully no one is running an HTTP server on port 4 QNetworkCacheMetaData metaData; metaData.setUrl(url); @@ -518,7 +518,7 @@ void tst_QNetworkDiskCache::expire() if (i % 3 == 0) QTest::qWait(2000); QNetworkCacheMetaData m; - m.setUrl(QUrl("http://www.foo.com/" + QString::number(i))); + m.setUrl(QUrl("http://localhost:4/" + QString::number(i))); QIODevice *d = cache.prepare(m); QString bigString; bigString.fill(QLatin1Char('Z'), (1024 * 1024 / 4)); @@ -540,7 +540,7 @@ void tst_QNetworkDiskCache::expire() std::sort(cacheList.begin(), cacheList.end()); for (int i = 0; i < cacheList.count(); ++i) { QString fileName = cacheList[i]; - QCOMPARE(fileName, QString("http://www.foo.com/%1").arg(i + 6)); + QCOMPARE(fileName, QString("http://localhost:4/%1").arg(i + 6)); } } From 88550543f8b4b7c76bffeebb923ad1f72b774b6e Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Tue, 3 Mar 2015 14:44:46 +0100 Subject: [PATCH 10/10] Painting: Avoid endless loop for certain bezier curves If the coordinates were too close (at the limit of the number accuracy), the splitting algorithm in QBezier::shifted() would never finish. Ref. testcase in bugreport. Task-number: QTBUG-44674 Change-Id: I2a575cdc6284504ef5e3eb2b749857576fe433c3 Reviewed-by: Gunnar Sletta --- src/gui/painting/qbezier.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/painting/qbezier.cpp b/src/gui/painting/qbezier.cpp index 90240d1752..a741c94c16 100644 --- a/src/gui/painting/qbezier.cpp +++ b/src/gui/painting/qbezier.cpp @@ -402,8 +402,8 @@ int QBezier::shifted(QBezier *curveSegments, int maxSegments, qreal offset, floa Q_ASSERT(curveSegments); Q_ASSERT(maxSegments > 0); - if (x1 == x2 && x1 == x3 && x1 == x4 && - y1 == y2 && y1 == y3 && y1 == y4) + if (qFuzzyCompare(x1, x2) && qFuzzyCompare(x1, x3) && qFuzzyCompare(x1, x4) && + qFuzzyCompare(y1, y2) && qFuzzyCompare(y1, y3) && qFuzzyCompare(y1, y4)) return 0; --maxSegments;