From 2833556a079defdb27c3dbe117ab66ea8080de75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Wed, 8 Jan 2014 11:20:19 +0100 Subject: [PATCH 01/26] Improve Mac OS X touch event enabling. Previously, the Qt Quick touch interaction items would enable touch events on window change. On app startup this would typically happen before the platform window was created, and the call to registerTouchWindow would then create the platform window. registerTouchWindow in QtBase has now been changed to not create the platform window since this has unwanted side effects. Calling it at window change time will then have no effect for the initial window change. Enable and disable touch events on hoverEnter/Leave instead. This is similar to what QtWidgets does and has an additional benefit: touch events can now be enabled when the mouse cursor is hovering over a touch item, reducing the chances of it interfering with scroll events for other items. Task-number: QTBUG-32988 Change-Id: Ic48dbec910f52299d5068f5ca7508be73cdc6f36 Reviewed-by: Shawn Rutledge --- src/quick/items/qquickmultipointtoucharea.cpp | 36 ++++++------ src/quick/items/qquickmultipointtoucharea_p.h | 9 +-- src/quick/items/qquickpincharea.cpp | 55 ++++++++++--------- src/quick/items/qquickpincharea_p.h | 9 +-- 4 files changed, 57 insertions(+), 52 deletions(-) diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp index 8fe306b006..e0eb641528 100644 --- a/src/quick/items/qquickmultipointtoucharea.cpp +++ b/src/quick/items/qquickmultipointtoucharea.cpp @@ -323,7 +323,6 @@ void QQuickTouchPoint::setSceneY(qreal sceneY) QQuickMultiPointTouchArea::QQuickMultiPointTouchArea(QQuickItem *parent) : QQuickItem(parent), - _currentWindow(0), _minimumTouchPoints(0), _maximumTouchPoints(INT_MAX), _stealMouse(false) @@ -333,8 +332,8 @@ QQuickMultiPointTouchArea::QQuickMultiPointTouchArea(QQuickItem *parent) if (qmlVisualTouchDebugging()) { setFlag(QQuickItem::ItemHasContents); } -#ifdef Q_OS_MAC - connect(this, &QQuickItem::windowChanged, this, &QQuickMultiPointTouchArea::setTouchEventsEnabledForWindow); +#ifdef Q_OS_OSX + setAcceptHoverEvents(true); // needed to enable touch events on mouse hover. #endif } @@ -547,28 +546,31 @@ void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p) _pressedTouchPoints.append(dtp); } -void QQuickMultiPointTouchArea::setTouchEventsEnabledForWindow(QWindow *window) +#ifdef Q_OS_OSX +void QQuickMultiPointTouchArea::hoverEnterEvent(QHoverEvent *event) +{ + Q_UNUSED(event); + setTouchEventsEnabled(true); +} + +void QQuickMultiPointTouchArea::hoverLeaveEvent(QHoverEvent *event) +{ + Q_UNUSED(event); + setTouchEventsEnabled(false); +} + +void QQuickMultiPointTouchArea::setTouchEventsEnabled(bool enable) { -#ifdef Q_OS_MAC // Resolve function for enabling touch events from the (cocoa) platform plugin. typedef void (*RegisterTouchWindowFunction)(QWindow *, bool); RegisterTouchWindowFunction registerTouchWindow = reinterpret_cast( QGuiApplication::platformNativeInterface()->nativeResourceFunctionForIntegration("registertouchwindow")); if (!registerTouchWindow) - return; // Not necessarily an error, Qt migh be using a different platform plugin. + return; // Not necessarily an error, Qt might be using a different platform plugin. - // Disable touch on the old window, enable on the new window. - if (_currentWindow) - registerTouchWindow(_currentWindow, false); - if (window) - registerTouchWindow(window, true); - // Save the current window, setTouchEventsEnabledForWindow will be called - // with a null window on disable. - _currentWindow = window; -#else // Q_OS_MAC - Q_UNUSED(window) -#endif + registerTouchWindow(window(), enable); } +#endif // Q_OS_OSX void QQuickMultiPointTouchArea::addTouchPrototype(QQuickTouchPoint *prototype) { diff --git a/src/quick/items/qquickmultipointtoucharea_p.h b/src/quick/items/qquickmultipointtoucharea_p.h index 2e1f2a98fb..83cc407401 100644 --- a/src/quick/items/qquickmultipointtoucharea_p.h +++ b/src/quick/items/qquickmultipointtoucharea_p.h @@ -250,9 +250,11 @@ protected: bool shouldFilter(QEvent *event); void grabGesture(); virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); - -protected Q_SLOTS: - void setTouchEventsEnabledForWindow(QWindow *window); +#ifdef Q_OS_OSX + void hoverEnterEvent(QHoverEvent *event); + void hoverLeaveEvent(QHoverEvent *event); + void setTouchEventsEnabled(bool enable); +#endif private: void ungrab(); @@ -261,7 +263,6 @@ private: QList _releasedTouchPoints; QList _pressedTouchPoints; QList _movedTouchPoints; - QWindow *_currentWindow; int _minimumTouchPoints; int _maximumTouchPoints; bool _stealMouse; diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp index 419792aaa5..f741a08512 100644 --- a/src/quick/items/qquickpincharea.cpp +++ b/src/quick/items/qquickpincharea.cpp @@ -248,14 +248,13 @@ QQuickPinchAreaPrivate::~QQuickPinchAreaPrivate() QQuickPinchArea::QQuickPinchArea(QQuickItem *parent) : QQuickItem(*(new QQuickPinchAreaPrivate), parent) - , _currentWindow(0) { Q_D(QQuickPinchArea); d->init(); setAcceptedMouseButtons(Qt::LeftButton); setFiltersChildMouseEvents(true); -#ifdef Q_OS_MAC - connect(this, &QQuickItem::windowChanged, this, &QQuickPinchArea::setTouchEventsEnabledForWindow); +#ifdef Q_OS_OSX + setAcceptHoverEvents(true); // needed to enable touch events on mouse hover. #endif } @@ -537,6 +536,32 @@ void QQuickPinchArea::itemChange(ItemChange change, const ItemChangeData &value) QQuickItem::itemChange(change, value); } +#ifdef Q_OS_OSX +void QQuickPinchArea::hoverEnterEvent(QHoverEvent *event) +{ + Q_UNUSED(event); + setTouchEventsEnabled(true); +} + +void QQuickPinchArea::hoverLeaveEvent(QHoverEvent *event) +{ + Q_UNUSED(event); + setTouchEventsEnabled(false); +} + +void QQuickPinchArea::setTouchEventsEnabled(bool enable) +{ + // Resolve function for enabling touch events from the (cocoa) platform plugin. + typedef void (*RegisterTouchWindowFunction)(QWindow *, bool); + RegisterTouchWindowFunction registerTouchWindow = reinterpret_cast( + QGuiApplication::platformNativeInterface()->nativeResourceFunctionForIntegration("registertouchwindow")); + if (!registerTouchWindow) + return; // Not necessarily an error, Qt might be using a different platform plugin. + + registerTouchWindow(window(), enable); +} +#endif // Q_OS_OSX + QQuickPinch *QQuickPinchArea::pinch() { Q_D(QQuickPinchArea); @@ -545,29 +570,5 @@ QQuickPinch *QQuickPinchArea::pinch() return d->pinch; } -void QQuickPinchArea::setTouchEventsEnabledForWindow(QWindow *window) -{ -#ifdef Q_OS_MAC - // Resolve function for enabling touch events from the (cocoa) platform plugin. - typedef void (*RegisterTouchWindowFunction)(QWindow *, bool); - RegisterTouchWindowFunction registerTouchWindow = reinterpret_cast( - QGuiApplication::platformNativeInterface()->nativeResourceFunctionForIntegration("registertouchwindow")); - if (!registerTouchWindow) - return; // Not necessarily an error, Qt migh be using a different platform plugin. - - // Disable touch on the old window, enable on the new window. - if (_currentWindow) - registerTouchWindow(_currentWindow, false); - if (window) - registerTouchWindow(window, true); - // Save the current window, setTouchEventsEnabledForWindow will be called - // with a null window on disable. - _currentWindow = window; -#else // Q_OS_MAC - Q_UNUSED(window) -#endif -} - - QT_END_NAMESPACE diff --git a/src/quick/items/qquickpincharea_p.h b/src/quick/items/qquickpincharea_p.h index c991145fc7..81bdbda3a1 100644 --- a/src/quick/items/qquickpincharea_p.h +++ b/src/quick/items/qquickpincharea_p.h @@ -282,9 +282,11 @@ protected: virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); virtual void itemChange(ItemChange change, const ItemChangeData& value); - -private Q_SLOTS: - void setTouchEventsEnabledForWindow(QWindow *window); +#ifdef Q_OS_OSX + void hoverEnterEvent(QHoverEvent *event); + void hoverLeaveEvent(QHoverEvent *event); + void setTouchEventsEnabled(bool enable); +#endif private: void updatePinch(); @@ -292,7 +294,6 @@ private: void handleRelease(); private: - QWindow *_currentWindow; Q_DISABLE_COPY(QQuickPinchArea) Q_DECLARE_PRIVATE(QQuickPinchArea) }; From da54d7f1a6f44a32c062094baf9ed1cb7156348d Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 4 Dec 2013 15:34:07 +0100 Subject: [PATCH 02/26] QQmlInstructionData: fix warning 'code' {is,might be} used uninit'ed This is a compile-error for -release -developer-build builds. Change-Id: I7ea5363260ce35a013fbf6d1c538c763023a8dc0 Reviewed-by: Simon Hausmann Reviewed-by: Lars Knoll --- src/qml/qml/qqmlinstruction_p.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/qml/qml/qqmlinstruction_p.h b/src/qml/qml/qqmlinstruction_p.h index bda8c3db0d..8b27cf06dd 100644 --- a/src/qml/qml/qqmlinstruction_p.h +++ b/src/qml/qml/qqmlinstruction_p.h @@ -151,8 +151,10 @@ QT_BEGIN_NAMESPACE #ifdef QML_THREADED_VME_INTERPRETER # define QML_INSTR_HEADER void *code; +# define QML_INSTR_HEADER_INIT this->code = 0; #else # define QML_INSTR_HEADER quint8 instructionType; +# define QML_INSTR_HEADER_INIT this->instructionType = 0; #endif #define QML_INSTR_ENUM(I, FMT) I, @@ -547,6 +549,8 @@ FOR_EACH_QML_INSTR(QML_INSTR_META_TEMPLATE); template class QQmlInstructionData : public QQmlInstructionMeta::DataType { +public: + QQmlInstructionData() : QQmlInstructionMeta::DataType() { QML_INSTR_HEADER_INIT } }; QT_END_NAMESPACE From ed7115ffde52c57a308199c3d279ea3c96668117 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 13 Jan 2014 11:56:59 +0100 Subject: [PATCH 03/26] Work around missing BGRA texture format on Samsung Galaxy Tab 3 The GL driver on the Galaxy Tab 3 reports support for the BGRA8888 texture format, but does not actually support it. For this particular device we disable support for that format. Task-number: QTBUG-34984 Change-Id: Ie26ef0e815c1622b3425c37237a3fc320543b92c Reviewed-by: Gunnar Sletta --- src/quick/scenegraph/util/qsgatlastexture.cpp | 18 +++++++++++++++--- src/quick/scenegraph/util/qsgtexture.cpp | 17 +++++++++++++++-- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp index 389945849f..378451c307 100644 --- a/src/quick/scenegraph/util/qsgatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgatlastexture.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include @@ -144,10 +145,21 @@ Atlas::Atlas(const QSize &size) { #ifdef QT_OPENGL_ES +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_NO_SDK) + QString *deviceName = + static_cast(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("AndroidDeviceName")); + static bool wrongfullyReportsBgra8888Support = deviceName->compare(QStringLiteral("samsung SM-T211"), Qt::CaseInsensitive) == 0 + || deviceName->compare(QStringLiteral("samsung SM-T210"), Qt::CaseInsensitive) == 0 + || deviceName->compare(QStringLiteral("samsung SM-T215"), Qt::CaseInsensitive) == 0; +#else + static bool wrongfullyReportsBgra8888Support = false; +#endif + const char *ext = (const char *) glGetString(GL_EXTENSIONS); - if (strstr(ext, "GL_EXT_bgra") - || strstr(ext, "GL_EXT_texture_format_BGRA8888") - || strstr(ext, "GL_IMG_texture_format_BGRA8888")) { + if (!wrongfullyReportsBgra8888Support + && (strstr(ext, "GL_EXT_bgra") + || strstr(ext, "GL_EXT_texture_format_BGRA8888") + || strstr(ext, "GL_IMG_texture_format_BGRA8888"))) { m_internalFormat = m_externalFormat = GL_BGRA; #ifdef Q_OS_IOS } else if (strstr(ext, "GL_APPLE_texture_format_BGRA8888")) { diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp index df724d8a01..04ffad7acf 100644 --- a/src/quick/scenegraph/util/qsgtexture.cpp +++ b/src/quick/scenegraph/util/qsgtexture.cpp @@ -47,6 +47,8 @@ #include #include #include +#include +#include #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) #define CAN_BACKTRACE_EXECINFO @@ -682,14 +684,25 @@ void QSGPlainTexture::bind() GLenum externalFormat = GL_RGBA; GLenum internalFormat = GL_RGBA; +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_NO_SDK) + QString *deviceName = + static_cast(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("AndroidDeviceName")); + static bool wrongfullyReportsBgra8888Support = deviceName->compare(QStringLiteral("samsung SM-T211"), Qt::CaseInsensitive) == 0 + || deviceName->compare(QStringLiteral("samsung SM-T210"), Qt::CaseInsensitive) == 0 + || deviceName->compare(QStringLiteral("samsung SM-T215"), Qt::CaseInsensitive) == 0; +#else + static bool wrongfullyReportsBgra8888Support = false; +#endif + QOpenGLContext *context = QOpenGLContext::currentContext(); if (context->hasExtension(QByteArrayLiteral("GL_EXT_bgra"))) { externalFormat = GL_BGRA; #ifdef QT_OPENGL_ES internalFormat = GL_BGRA; #endif - } else if (context->hasExtension(QByteArrayLiteral("GL_EXT_texture_format_BGRA8888")) - || context->hasExtension(QByteArrayLiteral("GL_IMG_texture_format_BGRA8888"))) { + } else if (!wrongfullyReportsBgra8888Support + && (context->hasExtension(QByteArrayLiteral("GL_EXT_texture_format_BGRA8888")) + || context->hasExtension(QByteArrayLiteral("GL_IMG_texture_format_BGRA8888")))) { externalFormat = GL_BGRA; internalFormat = GL_BGRA; #ifdef Q_OS_IOS From 0eabb34843cd282e10d96075a98f8795399bcd5d Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 17 Jan 2014 16:09:25 +0100 Subject: [PATCH 04/26] Fix uninitialized variable in debug builds Initialize size to zero in both constructors. This should fix UMRs. Change-Id: I6888f667b3dc6b2e72e58b54288c3c88df3ced71 Reviewed-by: Erik Verbruggen --- src/qml/jsruntime/qv4scopedvalue_p.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index 21f45745cb..2c71a36a3d 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -65,6 +65,9 @@ struct Scope { explicit Scope(ExecutionEngine *e) : engine(e) +#ifndef QT_NO_DEBUG + , size(0) +#endif { mark = engine->jsStackTop; } From 46ffd0e470b66e8cc501d5caf4ba92022d1ee474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kimmo=20Lepp=C3=A4l=C3=A4?= Date: Tue, 3 Sep 2013 09:59:34 +0300 Subject: [PATCH 05/26] QQmlEngine - fix example in documentation example_qjsvalue_singletontype_provider example code snippet returns QJSValue instead of QJSValue*. Change-Id: If4d5592fcee25ada9870602c8f92197980ef9b77 Reviewed-by: Nico Vertriest Reviewed-by: Gunnar Sletta --- src/qml/doc/src/qmlfunctions.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc index 19cd3b3f02..d3d3174193 100644 --- a/src/qml/doc/src/qmlfunctions.qdoc +++ b/src/qml/doc/src/qmlfunctions.qdoc @@ -238,7 +238,7 @@ Usage: \code // First, define the singleton type provider function (callback). - static QJSValue *example_qjsvalue_singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngine) + static QJSValue example_qjsvalue_singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngine) { Q_UNUSED(engine) From a5669568904b37b1d6b297e7190d18306e198604 Mon Sep 17 00:00:00 2001 From: Berthold Krevert Date: Thu, 16 Jan 2014 19:13:16 +0100 Subject: [PATCH 06/26] Remove redundant button clicked handler in QQuickMessageBox Change c286b4fccb2d83fcc01b21913b95c5e4f21f2982 added the QQuickAbstractMessageDialog::click() handler, which made the QQuickMessageDialog::clicked() handler redundant. Change-Id: Ifd770a3c67b35fd9a4929fc55b9e5298c36fb960 Task-number: QTBUG-35933 Reviewed-by: Liang Qi --- src/imports/dialogs/qquickmessagedialog.cpp | 48 --------------------- src/imports/dialogs/qquickmessagedialog_p.h | 1 - 2 files changed, 49 deletions(-) diff --git a/src/imports/dialogs/qquickmessagedialog.cpp b/src/imports/dialogs/qquickmessagedialog.cpp index 43b6ca09b4..5346aeeda8 100644 --- a/src/imports/dialogs/qquickmessagedialog.cpp +++ b/src/imports/dialogs/qquickmessagedialog.cpp @@ -93,7 +93,6 @@ QT_BEGIN_NAMESPACE QQuickMessageDialog::QQuickMessageDialog(QObject *parent) : QQuickAbstractMessageDialog(parent) { - connect(this, SIGNAL(buttonClicked()), this, SLOT(clicked())); } @@ -117,53 +116,6 @@ QQuickMessageDialog::~QQuickMessageDialog() \l Window or an \l Item. */ - -void QQuickMessageDialog::clicked() { - switch (m_clickedButton) { - // This mapping from buttons to roles is the same as - // documented for enum QMessageBox::StandardButton - case Ok: - case Open: - case Save: - case SaveAll: - case Retry: - case Ignore: - accept(); - break; - case Cancel: - case Close: - case Abort: - reject(); - break; - case Discard: - emit discard(); - close(); - break; - case Help: - emit help(); - break; - case Yes: - case YesToAll: - emit yes(); - close(); - break; - case No: - case NoToAll: - emit no(); - close(); - break; - case Apply: - emit apply(); - break; - case Reset: - case RestoreDefaults: - emit reset(); - break; - default: - qWarning("StandardButton %d has no role", m_clickedButton); - } -} - void QQuickMessageDialog::accept() { // enter key is treated like OK if (m_clickedButton == NoButton) diff --git a/src/imports/dialogs/qquickmessagedialog_p.h b/src/imports/dialogs/qquickmessagedialog_p.h index b21d8cba42..99c59ecca1 100644 --- a/src/imports/dialogs/qquickmessagedialog_p.h +++ b/src/imports/dialogs/qquickmessagedialog_p.h @@ -73,7 +73,6 @@ protected: protected Q_SLOTS: virtual void accept(); virtual void reject(); - void clicked(); private: Q_DISABLE_COPY(QQuickMessageDialog) From 19025ab3422658ab27415cee99336d88a4ae19fa Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 20 Jan 2014 14:32:26 +0100 Subject: [PATCH 07/26] Add support for deprecated RegExp (constructor) properties These were apparently part of ancient EcmaScript specs, aren't even listed anymore in any recent spec (not even as deprecated), but apparently they are part of what the web supports as well as previous versions of Qml. So this patch implements them. Task-number: QTBUG-36244 Change-Id: I1b9ea7ea09fceb6a486f615837a71e41aae12de4 Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4regexpobject.cpp | 93 +++++++++++++++++++++- src/qml/jsruntime/qv4regexpobject_p.h | 14 ++++ tests/auto/qml/qjsengine/tst_qjsengine.cpp | 64 +++++++++++++++ 3 files changed, 169 insertions(+), 2 deletions(-) diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 468fb34d76..0ebad2f781 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -238,6 +238,15 @@ RegExpCtor::RegExpCtor(ExecutionContext *scope) : FunctionObject(scope, QStringLiteral("RegExp")) { setVTable(&static_vtbl); + clearLastMatch(); +} + +void RegExpCtor::clearLastMatch() +{ + lastMatch = Primitive::nullValue(); + lastInput = engine()->newIdentifier(QString()); + lastMatchStart = 0; + lastMatchEnd = 0; } ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData) @@ -300,6 +309,14 @@ ReturnedValue RegExpCtor::call(Managed *that, CallData *callData) return construct(that, callData); } +void RegExpCtor::markObjects(Managed *that, ExecutionEngine *e) +{ + RegExpCtor *This = static_cast(that); + This->lastMatch.mark(e); + This->lastInput.mark(e); + FunctionObject::markObjects(that, e); +} + void RegExpPrototype::init(ExecutionEngine *engine, ObjectRef ctor) { Scope scope(engine); @@ -307,6 +324,28 @@ void RegExpPrototype::init(ExecutionEngine *engine, ObjectRef ctor) ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(2)); + + // Properties deprecated in the spec but required by "the web" :( + ctor->defineAccessorProperty(QStringLiteral("lastMatch"), method_get_lastMatch_n<0>, 0); + ctor->defineAccessorProperty(QStringLiteral("$&"), method_get_lastMatch_n<0>, 0); + ctor->defineAccessorProperty(QStringLiteral("$1"), method_get_lastMatch_n<1>, 0); + ctor->defineAccessorProperty(QStringLiteral("$2"), method_get_lastMatch_n<2>, 0); + ctor->defineAccessorProperty(QStringLiteral("$3"), method_get_lastMatch_n<3>, 0); + ctor->defineAccessorProperty(QStringLiteral("$4"), method_get_lastMatch_n<4>, 0); + ctor->defineAccessorProperty(QStringLiteral("$5"), method_get_lastMatch_n<5>, 0); + ctor->defineAccessorProperty(QStringLiteral("$6"), method_get_lastMatch_n<6>, 0); + ctor->defineAccessorProperty(QStringLiteral("$7"), method_get_lastMatch_n<7>, 0); + ctor->defineAccessorProperty(QStringLiteral("$8"), method_get_lastMatch_n<8>, 0); + ctor->defineAccessorProperty(QStringLiteral("$9"), method_get_lastMatch_n<9>, 0); + ctor->defineAccessorProperty(QStringLiteral("lastParen"), method_get_lastParen, 0); + ctor->defineAccessorProperty(QStringLiteral("$+"), method_get_lastParen, 0); + ctor->defineAccessorProperty(QStringLiteral("input"), method_get_input, 0); + ctor->defineAccessorProperty(QStringLiteral("$_"), method_get_input, 0); + ctor->defineAccessorProperty(QStringLiteral("leftContext"), method_get_leftContext, 0); + ctor->defineAccessorProperty(QStringLiteral("$`"), method_get_leftContext, 0); + ctor->defineAccessorProperty(QStringLiteral("rightContext"), method_get_rightContext, 0); + ctor->defineAccessorProperty(QStringLiteral("$'"), method_get_rightContext, 0); + defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); defineDefaultProperty(QStringLiteral("exec"), method_exec, 1); defineDefaultProperty(QStringLiteral("test"), method_test, 1); @@ -334,7 +373,11 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) } uint* matchOffsets = (uint*)alloca(r->value->captureCount() * 2 * sizeof(uint)); - int result = r->value->match(s, offset, matchOffsets); + const int result = r->value->match(s, offset, matchOffsets); + + Scoped regExpCtor(scope, ctx->engine->regExpCtor); + regExpCtor->clearLastMatch(); + if (result == -1) { r->lastIndexProperty(ctx)->value = Primitive::fromInt32(0); return Encode::null(); @@ -351,10 +394,14 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) array->arrayDataLen = i + 1; } array->setArrayLengthUnchecked(len); - array->memberData[Index_ArrayIndex].value = Primitive::fromInt32(result); array->memberData[Index_ArrayInput].value = arg.asReturnedValue(); + regExpCtor->lastMatch = array; + regExpCtor->lastInput = arg->stringValue(); + regExpCtor->lastMatchStart = matchOffsets[0]; + regExpCtor->lastMatchEnd = matchOffsets[1]; + if (r->global) r->lastIndexProperty(ctx)->value = Primitive::fromInt32(matchOffsets[1]); @@ -395,4 +442,46 @@ ReturnedValue RegExpPrototype::method_compile(CallContext *ctx) return Encode::undefined(); } +template +ReturnedValue RegExpPrototype::method_get_lastMatch_n(CallContext *ctx) +{ + Scope scope(ctx); + ScopedArrayObject lastMatch(scope, static_cast(ctx->engine->regExpCtor.objectValue())->lastMatch); + ScopedValue result(scope, lastMatch ? lastMatch->getIndexed(index) : Encode::undefined()); + if (result->isUndefined()) + return ctx->engine->newString(QString())->asReturnedValue(); + return result.asReturnedValue(); +} + +ReturnedValue RegExpPrototype::method_get_lastParen(CallContext *ctx) +{ + Scope scope(ctx); + ScopedArrayObject lastMatch(scope, static_cast(ctx->engine->regExpCtor.objectValue())->lastMatch); + ScopedValue result(scope, lastMatch ? lastMatch->getIndexed(lastMatch->arrayLength() - 1) : Encode::undefined()); + if (result->isUndefined()) + return ctx->engine->newString(QString())->asReturnedValue(); + return result.asReturnedValue(); +} + +ReturnedValue RegExpPrototype::method_get_input(CallContext *ctx) +{ + return static_cast(ctx->engine->regExpCtor.objectValue())->lastInput.asReturnedValue(); +} + +ReturnedValue RegExpPrototype::method_get_leftContext(CallContext *ctx) +{ + Scope scope(ctx); + Scoped regExpCtor(scope, ctx->engine->regExpCtor); + QString lastInput = regExpCtor->lastInput->toQString(); + return ctx->engine->newString(lastInput.left(regExpCtor->lastMatchStart))->asReturnedValue(); +} + +ReturnedValue RegExpPrototype::method_get_rightContext(CallContext *ctx) +{ + Scope scope(ctx); + Scoped regExpCtor(scope, ctx->engine->regExpCtor); + QString lastInput = regExpCtor->lastInput->toQString(); + return ctx->engine->newString(lastInput.mid(regExpCtor->lastMatchEnd))->asReturnedValue(); +} + QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index 0129f8d396..f112ad804d 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -106,8 +106,15 @@ struct RegExpCtor: FunctionObject Q_MANAGED RegExpCtor(ExecutionContext *scope); + SafeValue lastMatch; + SafeString lastInput; + int lastMatchStart; + int lastMatchEnd; + void clearLastMatch(); + static ReturnedValue construct(Managed *m, CallData *callData); static ReturnedValue call(Managed *that, CallData *callData); + static void markObjects(Managed *that, ExecutionEngine *e); }; struct RegExpPrototype: RegExpObject @@ -119,6 +126,13 @@ struct RegExpPrototype: RegExpObject static ReturnedValue method_test(CallContext *ctx); static ReturnedValue method_toString(CallContext *ctx); static ReturnedValue method_compile(CallContext *ctx); + + template + static ReturnedValue method_get_lastMatch_n(CallContext *ctx); + static ReturnedValue method_get_lastParen(CallContext *ctx); + static ReturnedValue method_get_input(CallContext *ctx); + static ReturnedValue method_get_leftContext(CallContext *ctx); + static ReturnedValue method_get_rightContext(CallContext *ctx); }; } diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index a1662b495c..ba99b34935 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -148,6 +148,8 @@ private slots: void functionDeclarationsInConditionals(); void arrayPop_QTBUG_35979(); + + void regexpLastMatch(); }; tst_QJSEngine::tst_QJSEngine() @@ -2705,6 +2707,68 @@ void tst_QJSEngine::arrayPop_QTBUG_35979() QCOMPARE(result.toString(), QString("1,3")); } +void tst_QJSEngine::regexpLastMatch() +{ + QJSEngine eng; + + QCOMPARE(eng.evaluate("RegExp.input").toString(), QString()); + + QJSValue hasProperty; + + for (int i = 1; i < 9; ++i) { + hasProperty = eng.evaluate("RegExp.hasOwnProperty(\"$" + QString::number(i) + "\")"); + QVERIFY(hasProperty.isBool()); + QVERIFY(hasProperty.toBool()); + } + + hasProperty = eng.evaluate("RegExp.hasOwnProperty(\"$0\")"); + QVERIFY(hasProperty.isBool()); + QVERIFY(!hasProperty.toBool()); + + hasProperty = eng.evaluate("RegExp.hasOwnProperty(\"$10\")"); + QVERIFY(!hasProperty.toBool()); + + hasProperty = eng.evaluate("RegExp.hasOwnProperty(\"lastMatch\")"); + QVERIFY(hasProperty.toBool()); + hasProperty = eng.evaluate("RegExp.hasOwnProperty(\"$&\")"); + QVERIFY(hasProperty.toBool()); + + QJSValue result = eng.evaluate("" + "var re = /h(el)l(o)/\n" + "var text = \"blah hello world\"\n" + "text.match(re)\n"); + QVERIFY(!result.isError()); + QJSValue match = eng.evaluate("RegExp.$1"); + QCOMPARE(match.toString(), QString("el")); + match = eng.evaluate("RegExp.$2"); + QCOMPARE(match.toString(), QString("o")); + for (int i = 3; i <= 9; ++i) { + match = eng.evaluate("RegExp.$" + QString::number(i)); + QVERIFY(match.isString()); + QCOMPARE(match.toString(), QString()); + } + QCOMPARE(eng.evaluate("RegExp.input").toString(), QString("blah hello world")); + QCOMPARE(eng.evaluate("RegExp.lastParen").toString(), QString("o")); + QCOMPARE(eng.evaluate("RegExp.leftContext").toString(), QString("blah ")); + QCOMPARE(eng.evaluate("RegExp.rightContext").toString(), QString(" world")); + + QCOMPARE(eng.evaluate("RegExp.lastMatch").toString(), QString("hello")); + + result = eng.evaluate("" + "var re = /h(ello)/\n" + "var text = \"hello\"\n" + "text.match(re)\n"); + QVERIFY(!result.isError()); + match = eng.evaluate("RegExp.$1"); + QCOMPARE(match.toString(), QString("ello")); + for (int i = 2; i <= 9; ++i) { + match = eng.evaluate("RegExp.$" + QString::number(i)); + QVERIFY(match.isString()); + QCOMPARE(match.toString(), QString()); + } + +} + QTEST_MAIN(tst_QJSEngine) #include "tst_qjsengine.moc" From 4c5cd2f04fdaf946cc67896db7c190a318811d86 Mon Sep 17 00:00:00 2001 From: Daniel Pesch Date: Mon, 20 Jan 2014 16:40:30 +0100 Subject: [PATCH 08/26] qmlplugindump: New component properties isCreatable and isSingleton Qmlplugindump tool does not generate information about singleton status and creatability from QML for a component. This patch adds two new boolean properties that contain this information. It is used by Momentics IDE for providing better code validation and could be used by QtCreator in future in similar way. Task-number: QTBUG-36139 Change-Id: If85374a1854aaa0727670b27df735d481cab5337 Signed-off-by: Daniel Pesch Reviewed-by: Fawzi Mohamed --- tools/qmlplugindump/main.cpp | 46 ++++++++++++++++++------- tools/qmlplugindump/qmlstreamwriter.cpp | 10 ++++++ tools/qmlplugindump/qmlstreamwriter.h | 2 ++ 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp index 6939ce92e2..89af0905d5 100644 --- a/tools/qmlplugindump/main.cpp +++ b/tools/qmlplugindump/main.cpp @@ -182,13 +182,20 @@ QByteArray convertToId(const QMetaObject *mo) return className; } -QSet collectReachableMetaObjects(QQmlEngine *engine, const QList &skip = QList()) +QSet collectReachableMetaObjects(QQmlEngine *engine, + QSet &noncreatables, + QSet &singletons, + const QList &skip = QList()) { QSet metas; metas.insert(FriendlyQObject::qtMeta()); QHash > extensions; foreach (const QQmlType *ty, QQmlMetaType::qmlTypes()) { + if (!ty->isCreatable()) + noncreatables.insert(ty->metaObject()); + if (ty->isSingleton()) + singletons.insert(ty->metaObject()); if (!ty->isComposite()) { qmlTypesByCppName[ty->metaObject()->className()].insert(ty); if (ty->isExtendedType()) @@ -406,6 +413,12 @@ public: qml->writeArrayBinding(QLatin1String("exports"), QStringList() << exportString); qml->writeArrayBinding(QLatin1String("exportMetaObjectRevisions"), QStringList() << QString::number(compositeType->minorVersion())); + if (compositeType->isCreatable()) + qml->writeIsCreatable(false); + + if (compositeType->isSingleton()) + qml->writeIsSingleton(true); + for (int index = mainMeta->classInfoCount() - 1 ; index >= 0 ; --index) { QMetaClassInfo classInfo = mainMeta->classInfo(index); if (QLatin1String(classInfo.name()) == QLatin1String("DefaultProperty")) { @@ -437,7 +450,7 @@ public: qml->writeEndObject(); } - void dump(const QMetaObject *meta) + void dump(const QMetaObject *meta, bool isUncreatable, bool isSingleton) { qml->writeStartObject("Component"); @@ -469,6 +482,12 @@ public: std::sort(exportStrings.begin(), exportStrings.end()); qml->writeArrayBinding(QLatin1String("exports"), exportStrings); + if (isUncreatable) + qml->writeIsCreatable(false); + + if (isSingleton) + qml->writeIsSingleton(true); + // write meta object revisions QStringList metaObjectRevisions; foreach (const QString &exportString, exportStrings) { @@ -622,7 +641,6 @@ private: } }; - enum ExitCode { EXIT_INVALIDARGUMENTS = 1, EXIT_SEGV = 2, @@ -642,12 +660,12 @@ void sigSegvHandler(int) { void printUsage(const QString &appName) { - qWarning() << qPrintable(QString( + std::cerr << qPrintable(QString( "Usage: %1 [-v] [-noinstantiate] [-defaultplatform] [-[non]relocatable] module.uri version [module/import/path]\n" " %1 [-v] [-noinstantiate] -path path/to/qmldir/directory [version]\n" " %1 [-v] -builtins\n" "Example: %1 Qt.labs.folderlistmodel 2.0 /home/user/dev/qt-install/imports").arg( - appName)); + appName)) << std::endl; } int main(int argc, char *argv[]) @@ -726,14 +744,14 @@ int main(int argc, char *argv[]) || arg == QLatin1String("-defaultplatform")) { continue; } else { - qWarning() << "Invalid argument: " << arg; + std::cerr << "Invalid argument: " << qPrintable(arg) << std::endl; return EXIT_INVALIDARGUMENTS; } } if (action == Uri) { if (positionalArgs.size() != 3 && positionalArgs.size() != 4) { - qWarning() << "Incorrect number of positional arguments"; + std::cerr << "Incorrect number of positional arguments" << std::endl; return EXIT_INVALIDARGUMENTS; } pluginImportUri = positionalArgs[1]; @@ -742,7 +760,7 @@ int main(int argc, char *argv[]) pluginImportPath = positionalArgs[3]; } else if (action == Path) { if (positionalArgs.size() != 2 && positionalArgs.size() != 3) { - qWarning() << "Incorrect number of positional arguments"; + std::cerr << "Incorrect number of positional arguments" << std::endl; return EXIT_INVALIDARGUMENTS; } pluginImportPath = QDir::fromNativeSeparators(positionalArgs[1]); @@ -750,7 +768,7 @@ int main(int argc, char *argv[]) pluginImportVersion = positionalArgs[2]; } else if (action == Builtins) { if (positionalArgs.size() != 1) { - qWarning() << "Incorrect number of positional arguments"; + std::cerr << "Incorrect number of positional arguments" << std::endl; return EXIT_INVALIDARGUMENTS; } } @@ -760,7 +778,7 @@ int main(int argc, char *argv[]) if (!pluginImportPath.isEmpty()) { QDir cur = QDir::current(); cur.cd(pluginImportPath); - pluginImportPath = cur.absolutePath(); + pluginImportPath = cur.canonicalPath(); QDir::setCurrent(pluginImportPath); engine.addImportPath(pluginImportPath); } @@ -779,7 +797,9 @@ int main(int argc, char *argv[]) } // find all QMetaObjects reachable from the builtin module - QSet defaultReachable = collectReachableMetaObjects(&engine); + QSet uncreatableMetas; + QSet singletonMetas; + QSet defaultReachable = collectReachableMetaObjects(&engine, uncreatableMetas, singletonMetas); QList defaultTypes = QQmlMetaType::qmlTypes(); // add some otherwise unreachable QMetaObjects @@ -831,7 +851,7 @@ int main(int argc, char *argv[]) } } - QSet candidates = collectReachableMetaObjects(&engine, defaultTypes); + QSet candidates = collectReachableMetaObjects(&engine, uncreatableMetas, singletonMetas, defaultTypes); candidates.subtract(defaultReachable); // Also eliminate meta objects with the same classname. @@ -873,7 +893,7 @@ int main(int argc, char *argv[]) if (relocatable) dumper.setRelocatableModuleUri(pluginImportUri); foreach (const QMetaObject *meta, nameToMeta) { - dumper.dump(meta); + dumper.dump(meta, uncreatableMetas.contains(meta), singletonMetas.contains(meta)); } foreach (const QQmlType *compositeType, qmlTypesByCompositeName) dumper.dumpComposite(&engine, compositeType, defaultReachableNames); diff --git a/tools/qmlplugindump/qmlstreamwriter.cpp b/tools/qmlplugindump/qmlstreamwriter.cpp index 629e30b814..44bdcfea74 100644 --- a/tools/qmlplugindump/qmlstreamwriter.cpp +++ b/tools/qmlplugindump/qmlstreamwriter.cpp @@ -183,6 +183,16 @@ void QmlStreamWriter::writePotentialLine(const QByteArray &line) } } +void QmlStreamWriter::writeIsCreatable(bool isCreatable) { + writeIndent(); + m_stream->write(QString("isCreatable: %1\n").arg(isCreatable ? "true" : "false").toUtf8()); +} + +void QmlStreamWriter::writeIsSingleton(bool isSingleton) { + writeIndent(); + m_stream->write(QString("isSingleton: %1\n").arg(isSingleton ? "true" : "false").toUtf8()); +} + void QmlStreamWriter::flushPotentialLinesWithNewlines() { if (m_maybeOneline) diff --git a/tools/qmlplugindump/qmlstreamwriter.h b/tools/qmlplugindump/qmlstreamwriter.h index 9d8052911c..ee5740a48b 100644 --- a/tools/qmlplugindump/qmlstreamwriter.h +++ b/tools/qmlplugindump/qmlstreamwriter.h @@ -63,6 +63,8 @@ public: void writeScriptObjectLiteralBinding(const QString &name, const QList > &keyValue); void writeArrayBinding(const QString &name, const QStringList &elements); void write(const QString &data); + void writeIsCreatable(bool isCreatable); + void writeIsSingleton(bool isSingleton); private: void writeIndent(); From 1b53fb1b6f00fe6bef787d385dddc48d52b090c6 Mon Sep 17 00:00:00 2001 From: Daniel Pesch Date: Mon, 20 Jan 2014 18:37:32 +0100 Subject: [PATCH 09/26] qmplugindump is not able to dump all registered components This patch implements a new function QQmlMetaType::qmlAllTypes() used by qmlplugindump that returns list of all registered components. Previous implementation used QQmlMetaType::qmlATypes() call that returned only components with defined QML name. Task-number: QTBUG-36199 Change-Id: I85acba61cfa511973a004934cf0650f38cc46ed9 Signed-off-by: Daniel Pesch Reviewed-by: Fawzi Mohamed --- src/qml/qml/qqmlmetatype.cpp | 11 +++++++++++ src/qml/qml/qqmlmetatype_p.h | 1 + tools/qmlplugindump/main.cpp | 16 ++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index ed0c0afd6f..37f26a236f 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -1835,6 +1835,17 @@ QList QQmlMetaType::qmlTypes() return data->nameToType.values(); } +/*! + Returns the list of all registered types. +*/ +QList QQmlMetaType::qmlAllTypes() +{ + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + + return data->types; +} + /*! Returns the list of registered QML singleton types. */ diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index 2f473f5f46..64f7702b64 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -80,6 +80,7 @@ public: static QList qmlTypeNames(); static QList qmlTypes(); static QList qmlSingletonTypes(); + static QList qmlAllTypes(); static QQmlType *qmlType(const QString &qualifiedName, int, int); static QQmlType *qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int, int); diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp index 89af0905d5..000af0a1d8 100644 --- a/tools/qmlplugindump/main.cpp +++ b/tools/qmlplugindump/main.cpp @@ -182,6 +182,20 @@ QByteArray convertToId(const QMetaObject *mo) return className; } + +// Collect all metaobjects for types registered with qmlRegisterType() without parameters +void collectReachableMetaObjectsWithoutQmlName( QSet& metas ) { + foreach (const QQmlType *ty, QQmlMetaType::qmlAllTypes()) { + if ( ! metas.contains(ty->metaObject()) ) { + if (!ty->isComposite()) { + collectReachableMetaObjects(ty, &metas); + } else { + qmlTypesByCompositeName[ty->elementName()] = ty; + } + } + } +} + QSet collectReachableMetaObjects(QQmlEngine *engine, QSet &noncreatables, QSet &singletons, @@ -298,6 +312,8 @@ QSet collectReachableMetaObjects(QQmlEngine *engine, } } + collectReachableMetaObjectsWithoutQmlName(metas); + return metas; } From 24c43a5748b850203dd4711de43b92122e0f6cd5 Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Tue, 21 Jan 2014 10:55:18 +0100 Subject: [PATCH 10/26] Make compile on DragonFly BSD. [ChangeLog][Platform Specific Changes][BSD] Fixed compile errors on DragonFly BSD and potentially FreeBSD. Task-number: QTBUG-35867 Change-Id: Iea90b93672c34f8a4b56e9afc4dbfb82cc993548 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4alloca_p.h | 2 ++ src/qml/jsruntime/qv4engine.cpp | 7 +++++++ src/qml/jsruntime/qv4mm.cpp | 8 ++++++++ 3 files changed, 17 insertions(+) diff --git a/src/qml/jsruntime/qv4alloca_p.h b/src/qml/jsruntime/qv4alloca_p.h index f507d174e1..e51c6dff00 100644 --- a/src/qml/jsruntime/qv4alloca_p.h +++ b/src/qml/jsruntime/qv4alloca_p.h @@ -50,7 +50,9 @@ # define alloca _alloca # endif #else +#if !defined(__FreeBSD__) && !defined(__DragonFly__) # include #endif +#endif #endif diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index ac18e56868..dc5a60b341 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -77,6 +77,9 @@ #if USE(PTHREADS) # include # include +#if HAVE(PTHREAD_NP_H) +# include +#endif #endif QT_BEGIN_NAMESPACE @@ -109,7 +112,11 @@ quintptr getStackLimit() # else void* stackBottom = 0; pthread_attr_t attr; +#if HAVE(PTHREAD_NP_H) && OS(FREEBSD) + if (pthread_attr_get_np(pthread_self(), &attr) == 0) { +#else if (pthread_getattr_np(pthread_self(), &attr) == 0) { +#endif size_t stackSize = 0; pthread_attr_getstack(&attr, &stackBottom, &stackSize); pthread_attr_destroy(&attr); diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/jsruntime/qv4mm.cpp index 9923c8834c..1d6347b335 100644 --- a/src/qml/jsruntime/qv4mm.cpp +++ b/src/qml/jsruntime/qv4mm.cpp @@ -67,6 +67,10 @@ #include // __tls() #endif +#if USE(PTHREADS) && HAVE(PTHREAD_NP_H) +#include +#endif + QT_BEGIN_NAMESPACE using namespace QV4; @@ -234,7 +238,11 @@ MemoryManager::MemoryManager() # else void* stackBottom = 0; pthread_attr_t attr; +#if HAVE(PTHREAD_NP_H) && OS(FREEBSD) + if (pthread_attr_get_np(pthread_self(), &attr) == 0) { +#else if (pthread_getattr_np(pthread_self(), &attr) == 0) { +#endif size_t stackSize = 0; pthread_attr_getstack(&attr, &stackBottom, &stackSize); pthread_attr_destroy(&attr); From d5f5b3f87dc376b237c81d150a8d36cbb525e12e Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 16 Dec 2013 16:19:56 +0100 Subject: [PATCH 11/26] Retrieve detailed location information when profiling signal handlers Use the Functions associated with signal handlers to find out which exact code is being executed. Task-number: QTCREATORBUG-11100 Change-Id: Idfae9d188b17977b55f551e6fe766042fe24e786 Reviewed-by: Simon Hausmann --- src/qml/debugger/qqmlprofilerservice_p.h | 19 +++++++++++++++---- src/qml/qml/qqmlboundsignal.cpp | 11 +++++++++++ src/qml/qml/qqmlboundsignal_p.h | 1 + 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/qml/debugger/qqmlprofilerservice_p.h b/src/qml/debugger/qqmlprofilerservice_p.h index 86807eacec..32b88e3ec3 100644 --- a/src/qml/debugger/qqmlprofilerservice_p.h +++ b/src/qml/debugger/qqmlprofilerservice_p.h @@ -55,6 +55,7 @@ #include #include +#include #include #include @@ -254,10 +255,20 @@ struct QQmlHandlingSignalProfiler { QQmlHandlingSignalProfiler(QQmlBoundSignalExpression *expression) { if (QQmlProfilerService::enabled) { - QQmlProfilerService::instance->startRange(QQmlProfilerService::HandlingSignal); - QQmlProfilerService::instance->rangeLocation(QQmlProfilerService::HandlingSignal, - expression->sourceFile(), expression->lineNumber(), - expression->columnNumber()); + QQmlProfilerService *service = QQmlProfilerService::instance; + service->startRange(QQmlProfilerService::HandlingSignal); + if (expression->sourceFile().isEmpty()) { + QV4::Function *function = expression->function(); + if (function) { + service->rangeLocation(QQmlProfilerService::HandlingSignal, + function->sourceFile(), function->compiledFunction->location.line, + function->compiledFunction->location.column); + } + } else { + service->rangeLocation(QQmlProfilerService::HandlingSignal, + expression->sourceFile(), expression->lineNumber(), + expression->columnNumber()); + } } } diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index 68160edf5e..bc56fe1f2d 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -136,6 +136,17 @@ QString QQmlBoundSignalExpression::expression() const } } +QV4::Function *QQmlBoundSignalExpression::function() const +{ + if (m_expressionFunctionValid) { + Q_ASSERT (context() && engine()); + QV4::Scope scope(QQmlEnginePrivate::get(engine())->v4engine()); + QV4::Scoped v(scope, m_v8function.value()); + return v ? v->function : 0; + } + return 0; +} + // Parts of this function mirror code in QQmlExpressionPrivate::value() and v8value(). // Changes made here may need to be made there and vice versa. void QQmlBoundSignalExpression::evaluate(void **a) diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h index feb79d5484..fe0dbd380e 100644 --- a/src/qml/qml/qqmlboundsignal_p.h +++ b/src/qml/qml/qqmlboundsignal_p.h @@ -90,6 +90,7 @@ public: quint16 lineNumber() const { return m_line; } quint16 columnNumber() const { return m_column; } QString expression() const; + QV4::Function *function() const; QObject *target() const { return m_target; } QQmlEngine *engine() const { return context() ? context()->engine : 0; } From 4cf8a6ad7189991ff6852f4096fa8673ffa98bf0 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 16 Dec 2013 15:30:22 +0100 Subject: [PATCH 12/26] Parse source location for signal handling functions Previously the source location of signal handlers was always line 0 and column 0. This poses problems when trying to extract meaningful profiling information. The change assigns the source location of the statement declaring the function as the function's source location. Task-number: QTCREATORBUG-11100 Change-Id: I4bb8682b35147a7cfe4ecec342d4a00623bb1e0d Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlcompiler.cpp | 1 + .../data/signalSourceLocation.qml | 9 ++++++ .../qqmlprofilerservice.pro | 3 +- .../tst_qqmlprofilerservice.cpp | 30 +++++++++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 tests/auto/qml/debugger/qqmlprofilerservice/data/signalSourceLocation.qml diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp index 3dd9d6a14d..71e803a4c8 100644 --- a/src/qml/qml/qqmlcompiler.cpp +++ b/src/qml/qml/qqmlcompiler.cpp @@ -1681,6 +1681,7 @@ static AST::FunctionDeclaration *convertSignalHandlerExpressionToFunctionDeclara AST::FunctionBody *body = new (pool) AST::FunctionBody(elements); AST::FunctionDeclaration *functionDeclaration = new (pool) AST::FunctionDeclaration(jsEngine->newStringRef(signalName), paramList, body); + functionDeclaration->functionToken = statement->firstSourceLocation(); return functionDeclaration; } diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/signalSourceLocation.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/signalSourceLocation.qml new file mode 100644 index 0000000000..25e63669c4 --- /dev/null +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/signalSourceLocation.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 + +Rectangle { + width: 400 + height: 400 + + onWidthChanged: console.log(width); + Component.onCompleted: width = 500; +} diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro b/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro index a83927e720..d08ed31e8b 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro +++ b/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro @@ -15,4 +15,5 @@ DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 OTHER_FILES += \ data/pixmapCacheTest.qml \ - data/controlFromJS.qml + data/controlFromJS.qml \ + data/signalSourceLocation.qml diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp index acbc62807b..276dcf5d29 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp +++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp @@ -181,6 +181,7 @@ private slots: void scenegraphData(); void profileOnExit(); void controlFromJS(); + void signalSourceLocation(); }; void QQmlProfilerClient::messageReceived(const QByteArray &message) @@ -513,6 +514,35 @@ void tst_QQmlProfilerService::controlFromJS() QCOMPARE(m_client->traceMessages.last().detailType, (int)QQmlProfilerClient::EndTrace); } +void tst_QQmlProfilerService::signalSourceLocation() +{ + connect(true, "signalSourceLocation.qml"); + QVERIFY(m_client); + QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled); + + m_client->setTraceState(true); + while (!(m_process->output().contains(QLatin1String("500")))) + QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput()))); + m_client->setTraceState(false); + QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time."); + + // must start with "StartTrace" + QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event); + QCOMPARE(m_client->traceMessages.first().detailType, (int)QQmlProfilerClient::StartTrace); + + QVERIFY(m_client->traceMessages[14].detailData.endsWith("signalSourceLocation.qml")); + QVERIFY(m_client->traceMessages[14].line == 8); + QVERIFY(m_client->traceMessages[14].column == 28); + + QVERIFY(m_client->traceMessages[16].detailData.endsWith("signalSourceLocation.qml")); + QVERIFY(m_client->traceMessages[16].line == 7); + QVERIFY(m_client->traceMessages[16].column == 21); + + // must end with "EndTrace" + QCOMPARE(m_client->traceMessages.last().messageType, (int)QQmlProfilerClient::Event); + QCOMPARE(m_client->traceMessages.last().detailType, (int)QQmlProfilerClient::EndTrace); +} + QTEST_MAIN(tst_QQmlProfilerService) #include "tst_qqmlprofilerservice.moc" From 918159a2aae5062935a946e6d64120769802d625 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Tue, 21 Jan 2014 16:12:48 +1000 Subject: [PATCH 13/26] Ensure Flickable bounds detection is executed at the end of animation. In pixelAligned mode the content position when animating is rounded to a whole pixel, so the contentItem may reach the bound before the animation completes. Ensure bounds detection is run on animation completion. Task-number: QTBUG-36300 Change-Id: I083ff6a03a5d1b9ca9e2201487b602f1588002be Reviewed-by: Robin Burchell Reviewed-by: Joona Petrell --- src/quick/items/qquickflickable.cpp | 1 + .../qquickflickable/tst_qquickflickable.cpp | 38 +++++++++++++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 7cc37e0556..333c11cb29 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -2309,6 +2309,7 @@ void QQuickFlickable::timelineCompleted() return; } movementEnding(); + d->updateBeginningEnd(); } void QQuickFlickable::movementStarting() diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index 86321c775e..59b54e7ba5 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -1440,17 +1440,23 @@ void tst_qquickflickable::stopAtBounds_data() { QTest::addColumn("transpose"); QTest::addColumn("invert"); + QTest::addColumn("pixelAligned"); - QTest::newRow("left") << false << false; - QTest::newRow("right") << false << true; - QTest::newRow("top") << true << false; - QTest::newRow("bottom") << true << true; + QTest::newRow("left") << false << false << false; + QTest::newRow("right") << false << true << false; + QTest::newRow("top") << true << false << false; + QTest::newRow("bottom") << true << true << false; + QTest::newRow("left,pixelAligned") << false << false << true; + QTest::newRow("right,pixelAligned") << false << true << true; + QTest::newRow("top,pixelAligned") << true << false << true; + QTest::newRow("bottom,pixelAligned") << true << true << true; } void tst_qquickflickable::stopAtBounds() { QFETCH(bool, transpose); QFETCH(bool, invert); + QFETCH(bool, pixelAligned); QQuickView view; view.setSource(testFileUrl("stopAtBounds.qml")); @@ -1469,6 +1475,7 @@ void tst_qquickflickable::stopAtBounds() flickable->setContentY(invert ? 100 : 0); else flickable->setContentX(invert ? 100 : 0); + flickable->setPixelAligned(pixelAligned); const int threshold = qApp->styleHints()->startDragDistance(); @@ -1518,6 +1525,29 @@ void tst_qquickflickable::stopAtBounds() } QTest::mouseRelease(&view, Qt::LeftButton, 0, position); + + if (transpose) { + flickable->setContentY(invert ? 100 : 0); + } else { + flickable->setContentX(invert ? 100 : 0); + } + if (invert) + flick(&view, QPoint(20,20), QPoint(100,100), 100); + else + flick(&view, QPoint(100,100), QPoint(20,20), 100); + + QVERIFY(flickable->isFlicking()); + if (transpose) { + if (invert) + QTRY_COMPARE(flickable->isAtYBeginning(), true); + else + QTRY_COMPARE(flickable->isAtYEnd(), true); + } else { + if (invert) + QTRY_COMPARE(flickable->isAtXBeginning(), true); + else + QTRY_COMPARE(flickable->isAtXEnd(), true); + } } void tst_qquickflickable::nestedMouseAreaUsingTouch() From e7ad7739c4886236ea1b8e3149d76dcee8f9d11e Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Tue, 21 Jan 2014 13:28:53 +0100 Subject: [PATCH 14/26] Make it possible to render without a depth buffer. Some GL implementations (especially on embedded) will give us an OpenGL context without a depth buffer. In low memory scenarios, it might also be feasible to request a non-depth buffer context to save the depth buffer memory. The renderer deals with this by treating all nodes as translucent, by not adjusting the shaders and by not creating the extra z-order vertex attribute for merged nodes. Change-Id: I8edc92d530daa3e2628df2ba52901b47d87eaf26 Reviewed-by: Laszlo Agocs --- .../scenegraph/coreapi/qsgbatchrenderer.cpp | 61 ++++++++++++------- .../scenegraph/coreapi/qsgbatchrenderer_p.h | 2 + src/quick/scenegraph/qsgcontext.cpp | 21 +++++-- 3 files changed, 55 insertions(+), 29 deletions(-) diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index e9d883f248..a10191ec16 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -757,6 +757,7 @@ Renderer::Renderer(QSGRenderContext *ctx) , m_nextRenderOrder(0) , m_partialRebuild(false) , m_partialRebuildRoot(0) + , m_useDepthBuffer(true) , m_opaqueBatches(16) , m_alphaBatches(16) , m_batchPool(16) @@ -815,6 +816,8 @@ Renderer::Renderer(QSGRenderContext *ctx) m_vao = new QOpenGLVertexArrayObject(this); m_vao->create(); } + + m_useDepthBuffer = ctx->openglContext()->format().depthBufferSize() > 0; } static void qsg_wipeBuffer(Buffer *buffer, QOpenGLFunctions *funcs) @@ -1256,7 +1259,7 @@ void Renderer::buildRenderLists(QSGNode *node) Q_ASSERT(e); bool opaque = gn->inheritedOpacity() > OPAQUE_LIMIT && !(gn->activeMaterial()->flags() & QSGMaterial::Blending); - if (opaque) + if (opaque && m_useDepthBuffer) m_opaqueRenderList << e; else m_alphaRenderList << e; @@ -1637,10 +1640,13 @@ void Renderer::uploadMergedElement(Element *e, int vaOffset, char **vertexData, } } - float *vzorder = (float *) *zData; - float zorder = 1.0f - e->order * m_zRange; - for (int i=0; iorder * m_zRange; + for (int i=0; iindexCount(); quint16 *indices = (quint16 *) *indexData; @@ -1664,7 +1670,6 @@ void Renderer::uploadMergedElement(Element *e, int vaOffset, char **vertexData, } *vertexData += vCount * vSize; - *zData += vCount * sizeof(float); *indexData += iCount * sizeof(quint16); *iBase += vCount; *indexCount += iCount; @@ -1760,8 +1765,9 @@ void Renderer::uploadBatch(Batch *b) int bufferSize = b->vertexCount * g->sizeOfVertex(); int ibufferSize = 0; if (b->merged) { - bufferSize += b->vertexCount * sizeof(float); ibufferSize = b->indexCount * sizeof(quint16); + if (m_useDepthBuffer) + bufferSize += b->vertexCount * sizeof(float); } else { ibufferSize = unmergedIndexSize; } @@ -1783,7 +1789,7 @@ void Renderer::uploadBatch(Batch *b) #ifdef QSG_SEPARATE_INDEX_BUFFER char *indexData = b->ibo.data; #else - char *indexData = zData + b->vertexCount * sizeof(float); + char *indexData = zData + (m_useDepthBuffer ? b->vertexCount * sizeof(float) : 0); #endif quint16 iOffset = 0; @@ -1863,7 +1869,7 @@ void Renderer::uploadBatch(Batch *b) dump << ") "; offset += attr.tupleSize * size_of_type(attr.type); } - if (b->merged) { + if (b->merged && m_useDepthBuffer) { float zorder = ((float*)(b->vbo.data + b->vertexCount * g->sizeOfVertex()))[i]; dump << " Z:(" << zorder << ")"; } @@ -2031,7 +2037,7 @@ void Renderer::renderMergedBatch(const Batch *batch) QSGMaterial *material = gn->activeMaterial(); - ShaderManager::Shader *sms = m_shaderManager->prepareMaterial(material); + ShaderManager::Shader *sms = m_useDepthBuffer ? m_shaderManager->prepareMaterial(material) : m_shaderManager->prepareMaterialNoRewrite(material); QSGMaterialShader *program = sms->program; if (m_currentShader != sms) @@ -2060,7 +2066,8 @@ void Renderer::renderMergedBatch(const Batch *batch) glVertexAttribPointer(a.position, a.tupleSize, a.type, normalize, g->sizeOfVertex(), (void *) (qintptr) (offset + draw.vertices)); offset += a.tupleSize * size_of_type(a.type); } - glVertexAttribPointer(sms->pos_order, 1, GL_FLOAT, false, 0, (void *) (qintptr) (draw.zorders)); + if (m_useDepthBuffer) + glVertexAttribPointer(sms->pos_order, 1, GL_FLOAT, false, 0, (void *) (qintptr) (draw.zorders)); glDrawElements(g->drawingMode(), draw.indexCount, GL_UNSIGNED_SHORT, (void *) (qintptr) (indexBase + draw.indices)); } @@ -2142,8 +2149,10 @@ void Renderer::renderUnmergedBatch(const Batch *batch) m_current_determinant = m_current_model_view_matrix.determinant(); m_current_projection_matrix = projectionMatrix(); - m_current_projection_matrix(2, 2) = m_zRange; - m_current_projection_matrix(2, 3) = 1.0f - e->order * m_zRange; + if (m_useDepthBuffer) { + m_current_projection_matrix(2, 2) = m_zRange; + m_current_projection_matrix(2, 3) = 1.0f - e->order * m_zRange; + } program->updateState(state(dirty), material, m_currentMaterial); @@ -2197,17 +2206,22 @@ void Renderer::renderBatches() QRect r = viewportRect(); glViewport(r.x(), deviceRect().bottom() - r.bottom(), r.width(), r.height()); glClearColor(clearColor().redF(), clearColor().greenF(), clearColor().blueF(), clearColor().alphaF()); -#if defined(QT_OPENGL_ES) - glClearDepthf(1); -#else - glClearDepth(1); -#endif + if (m_useDepthBuffer) { +#if defined(QT_OPENGL_ES) + glClearDepthf(1); +#else + glClearDepth(1); +#endif + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glDepthMask(true); + glDisable(GL_BLEND); + } else { + glDisable(GL_DEPTH_TEST); + glDepthMask(false); + } glDisable(GL_CULL_FACE); - glDisable(GL_BLEND); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - glDepthMask(true); glColorMask(true, true, true, true); glDisable(GL_SCISSOR_TEST); glDisable(GL_STENCIL_TEST); @@ -2234,7 +2248,8 @@ void Renderer::renderBatches() } glEnable(GL_BLEND); - glDepthMask(false); + if (m_useDepthBuffer) + glDepthMask(false); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); if (Q_LIKELY(renderAlpha)) { diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h index 001c3b21ab..a0fa96f989 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h @@ -460,6 +460,8 @@ private: bool m_partialRebuild; QSGNode *m_partialRebuildRoot; + bool m_useDepthBuffer; + QHash m_renderNodeElements; QDataBuffer m_opaqueBatches; QDataBuffer m_alphaBatches; diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index 90803db9fe..1eeb9441b8 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -210,10 +210,17 @@ void QSGContext::renderContextInitialized(QSGRenderContext *renderContext) static bool dumped = false; if (!dumped && qEnvironmentVariableIsSet("QSG_INFO")) { dumped = true; - qDebug() << "GL_VENDOR: " << (const char *) glGetString(GL_VENDOR); - qDebug() << "GL_RENDERER: " << (const char *) glGetString(GL_RENDERER); - qDebug() << "GL_VERSION: " << (const char *) glGetString(GL_VERSION); - qDebug() << "GL_EXTENSIONS:\n " << QByteArray((const char *) glGetString(GL_EXTENSIONS)).replace(" ", "\n ").constData(); + QSurfaceFormat format = renderContext->openglContext()->format(); + qDebug() << "R/G/B/A Buffers: " << format.redBufferSize() << format.greenBufferSize() << format.blueBufferSize() << format.alphaBufferSize(); + qDebug() << "Depth Buffer: " << format.depthBufferSize(); + qDebug() << "Stencil Buffer: " << format.stencilBufferSize(); + qDebug() << "Samples: " << format.samples(); + qDebug() << "GL_VENDOR: " << (const char *) glGetString(GL_VENDOR); + qDebug() << "GL_RENDERER: " << (const char *) glGetString(GL_RENDERER); + qDebug() << "GL_VERSION: " << (const char *) glGetString(GL_VERSION); + QSet exts = renderContext->openglContext()->extensions(); + QByteArray all; foreach (const QByteArray &e, exts) all += ' ' + e; + qDebug() << "GL_EXTENSIONS: " << all.constData(); } d->mutex.unlock(); @@ -282,8 +289,10 @@ QSGGlyphNode *QSGContext::createGlyphNode(QSGRenderContext *rc) QSurfaceFormat QSGContext::defaultSurfaceFormat() const { QSurfaceFormat format; - format.setDepthBufferSize(24); - format.setStencilBufferSize(8); + static bool useDepth = qEnvironmentVariableIsEmpty("QSG_NO_DEPTH_BUFFER"); + static bool useStencil = qEnvironmentVariableIsEmpty("QSG_NO_STENCIL_BUFFER"); + format.setDepthBufferSize(useDepth ? 24 : 0); + format.setStencilBufferSize(useStencil ? 8 : 0); if (QQuickWindow::hasDefaultAlphaBuffer()) format.setAlphaBufferSize(8); format.setSwapBehavior(QSurfaceFormat::DoubleBuffer); From abc1cb32727a94ddac07020759c3c97382477cf9 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Tue, 21 Jan 2014 15:57:19 +0100 Subject: [PATCH 15/26] Revert QSGRenderNode to the old "in context" behavior There is already a lot of code out there that makes use of the rendernode hook and some of it is not capable of dealing with the render target being something other than 0. (Mozilla in this case). By forcing everything into the "alpha" code path, the hit on the renderer should be fairly minimal as long as render nodes are kept to a minimum, so reverting back to the ugly old behavior is acceptable. The API is still internal and highly discouraged. Change-Id: Ie35484f52da6b0420257c95710fdda07a2be2c23 Reviewed-by: Laszlo Agocs --- .../scenegraph/coreapi/qsgbatchrenderer.cpp | 140 +++++++----------- .../scenegraph/coreapi/qsgbatchrenderer_p.h | 6 +- 2 files changed, 56 insertions(+), 90 deletions(-) diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index a10191ec16..52a293871c 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -605,11 +605,6 @@ void Element::computeBounds() boundsOutsideFloatRange = bounds.isOutsideFloatRange(); } -RenderNodeElement::~RenderNodeElement() -{ - delete fbo; -} - bool Batch::isMaterialCompatible(Element *e) const { // If material has changed between opaque and translucent, it is not compatible @@ -768,6 +763,8 @@ Renderer::Renderer(QSGRenderContext *ctx) , m_zRange(0) , m_currentMaterial(0) , m_currentShader(0) + , m_currentClip(0) + , m_currentClipType(NoClip) , m_vao(0) { setNodeUpdater(new Updater(this)); @@ -1014,6 +1011,8 @@ void Renderer::nodeWasAdded(QSGNode *node, Node *shadowParent) snode->data = e; Q_ASSERT(!m_renderNodeElements.contains(static_cast(node))); m_renderNodeElements.insert(e->renderNode, e); + m_useDepthBuffer = false; + m_rebuild |= FullRebuild; } QSGNODE_TRAVERSE(node) @@ -1919,10 +1918,10 @@ void Renderer::updateClip(const QSGClipNode *clipList, const Batch *batch) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); if (batch->isOpaque) glDisable(GL_DEPTH_TEST); - ClipType type = updateStencilClip(m_currentClip); + m_currentClipType = updateStencilClip(m_currentClip); if (batch->isOpaque) { glEnable(GL_DEPTH_TEST); - if (type & StencilClip) + if (m_currentClipType & StencilClip) glDepthMask(true); } } @@ -2198,11 +2197,6 @@ void Renderer::renderBatches() << " -> Alpha: " << qsg_countNodesInBatches(m_alphaBatches) << " nodes in " << m_alphaBatches.size() << " batches..."; } - for (QHash::const_iterator it = m_renderNodeElements.constBegin(); - it != m_renderNodeElements.constEnd(); ++it) { - prepareRenderNode(it.value()); - } - QRect r = viewportRect(); glViewport(r.x(), deviceRect().bottom() - r.bottom(), r.width(), r.height()); glClearColor(clearColor().redF(), clearColor().greenF(), clearColor().blueF(), clearColor().alphaF()); @@ -2269,7 +2263,6 @@ void Renderer::renderBatches() updateStencilClip(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } void Renderer::deleteRemovedElements() @@ -2421,33 +2414,15 @@ void Renderer::render() m_vao->release(); } -void Renderer::prepareRenderNode(RenderNodeElement *e) +void Renderer::renderRenderNode(Batch *batch) { - if (e->fbo && e->fbo->size() != deviceRect().size()) { - delete e->fbo; - e->fbo = 0; - } + if (Q_UNLIKELY(debug_render)) + qDebug() << " -" << batch << "rendernode"; - if (!e->fbo) - e->fbo = new QOpenGLFramebufferObject(deviceRect().size(), QOpenGLFramebufferObject::CombinedDepthStencil); - e->fbo->bind(); + Q_ASSERT(batch->first->isRenderNode); + RenderNodeElement *e = (RenderNodeElement *) batch->first; - glDisable(GL_STENCIL_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_DEPTH_TEST); - glDisable(GL_BLEND); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); - - QSGRenderNode::RenderState state; - QMatrix4x4 pm = projectionMatrix(); - state.projectionMatrix = ± - state.scissorEnabled = false; - state.stencilEnabled = false; + setActiveShader(0, 0); QSGNode *clip = e->renderNode->parent(); e->renderNode->m_clip_list = 0; @@ -2459,6 +2434,16 @@ void Renderer::prepareRenderNode(RenderNodeElement *e) clip = clip->parent(); } + updateClip(e->renderNode->m_clip_list, batch); + + QSGRenderNode::RenderState state; + QMatrix4x4 pm = projectionMatrix(); + state.projectionMatrix = ± + state.scissorEnabled = m_currentClipType & ScissorClip; + state.stencilEnabled = m_currentClipType & StencilClip; + state.scissorRect = m_current_scissor_rect; + state.stencilValue = m_current_stencil_value; + QSGNode *xform = e->renderNode->parent(); QMatrix4x4 matrix; while (xform != rootNode()) { @@ -2480,66 +2465,51 @@ void Renderer::prepareRenderNode(RenderNodeElement *e) opacity = opacity->parent(); } + glDisable(GL_STENCIL_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_DEPTH_TEST); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + e->renderNode->render(state); e->renderNode->m_matrix = 0; + e->renderNode->m_clip_list = 0; - bindable()->bind(); -} - -void Renderer::renderRenderNode(Batch *batch) -{ - updateStencilClip(0); - m_currentClip = 0; - - setActiveShader(0, 0); - - if (!m_shaderManager->blitProgram) { - m_shaderManager->blitProgram = new QOpenGLShaderProgram(); - - QSGShaderSourceBuilder::initializeProgramFromFiles( - m_shaderManager->blitProgram, - QStringLiteral(":/scenegraph/shaders/rendernode.vert"), - QStringLiteral(":/scenegraph/shaders/rendernode.frag")); - m_shaderManager->blitProgram->bindAttributeLocation("av", 0); - m_shaderManager->blitProgram->bindAttributeLocation("at", 1); - m_shaderManager->blitProgram->link(); - - Q_ASSERT(m_shaderManager->blitProgram->isLinked()); + QSGRenderNode::StateFlags changes = e->renderNode->changedStates(); + if (changes & QSGRenderNode::ViewportState) { + QRect r = viewportRect(); + glViewport(r.x(), deviceRect().bottom() - r.bottom(), r.width(), r.height()); } - RenderNodeElement *e = static_cast(batch->first); - glBindTexture(GL_TEXTURE_2D, e->fbo->texture()); + if (changes & QSGRenderNode::StencilState) { + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilMask(0xff); + glDisable(GL_STENCIL_TEST); + } - m_shaderManager->blitProgram->bind(); + if (changes & (QSGRenderNode::StencilState | QSGRenderNode::ScissorState)) { + glDisable(GL_SCISSOR_TEST); + m_currentClip = 0; + m_currentClipType = NoClip; + } - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + if (changes & QSGRenderNode::DepthState) + glDisable(GL_DEPTH_TEST); - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); + if (changes & QSGRenderNode::ColorState) + bindable()->reactivate(); - float z = 1.0f - e->order * m_zRange; + if (changes & QSGRenderNode::BlendState) { + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } - float av[] = { -1, -1, z, - 1, -1, z, - -1, 1, z, - 1, 1, z }; - float at[] = { 0, 0, - 1, 0, - 0, 1, - 1, 1 }; + if (changes & QSGRenderNode::CullState) { + glFrontFace(isMirrored() ? GL_CW : GL_CCW); + glDisable(GL_CULL_FACE); + } - glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, av); - glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, at); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - glDisableVertexAttribArray(0); - glDisableVertexAttribArray(1); - glBindTexture(GL_TEXTURE_2D, 0); } QT_END_NAMESPACE diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h index a0fa96f989..0aa84da185 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h @@ -194,15 +194,11 @@ struct RenderNodeElement : public Element { RenderNodeElement(QSGRenderNode *rn) : Element(0) , renderNode(rn) - , fbo(0) { isRenderNode = true; } - ~RenderNodeElement(); - QSGRenderNode *renderNode; - QOpenGLFramebufferObject *fbo; }; struct BatchRootInfo { @@ -436,7 +432,6 @@ private: void renderUnmergedBatch(const Batch *batch); void updateClip(const QSGClipNode *clipList, const Batch *batch); const QMatrix4x4 &matrixForRoot(Node *node); - void prepareRenderNode(RenderNodeElement *e); void renderRenderNode(Batch *batch); void setActiveShader(QSGMaterialShader *program, ShaderManager::Shader *shader); @@ -485,6 +480,7 @@ private: QSGMaterialShader *m_currentProgram; ShaderManager::Shader *m_currentShader; const QSGClipNode *m_currentClip; + ClipType m_currentClipType; // For minimal OpenGL core profile support QOpenGLVertexArrayObject *m_vao; From 52a9d06bb028a16d9cf9be563a8ad1df09023439 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Wed, 22 Jan 2014 10:26:14 +0100 Subject: [PATCH 16/26] Enforce texture cleanup to happen at the end of the sync phase. This was ok for the threaded renderer, but for the single-threaded renderers where the event loop was spinning we could run the risk of scheduling a texture for deleteLater() and then cleaning it up before we got around to the sync phase. Task-number: QTBUG-35670 Change-Id: I92074294b427fd8ab2a1823ba79c7ac3b59094ec Reviewed-by: Michael Brasser --- src/quick/items/qquickwindow.cpp | 2 ++ src/quick/scenegraph/qsgcontext.cpp | 13 ++++++++++--- src/quick/scenegraph/qsgcontext_p.h | 2 ++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index d286ccff0c..532021932f 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -341,6 +341,8 @@ void QQuickWindowPrivate::syncSceneGraph() if (clearBeforeRendering) mode |= QSGRenderer::ClearColorBuffer; renderer->setClearMode(mode); + + context->endSync(); } diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index 1eeb9441b8..829d33a0d7 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -358,6 +358,12 @@ QSGRenderContext::~QSGRenderContext() invalidate(); } +void QSGRenderContext::endSync() +{ + qDeleteAll(m_texturesToDelete); + m_texturesToDelete.clear(); +} + static QBasicMutex qsg_framerender_mutex; void QSGRenderContext::renderNextFrame(QSGRenderer *renderer, GLuint fboId) @@ -475,6 +481,9 @@ void QSGRenderContext::invalidate() if (!m_gl) return; + qDeleteAll(m_texturesToDelete); + m_texturesToDelete.clear(); + qDeleteAll(m_textures.values()); m_textures.clear(); @@ -617,10 +626,8 @@ QSGTexture *QSGRenderContext::textureForFactory(QQuickTextureFactory *factory, Q void QSGRenderContext::textureFactoryDestroyed(QObject *o) { m_mutex.lock(); - QSGTexture *t = m_textures.take(static_cast(o)); + m_texturesToDelete << m_textures.take(static_cast(o)); m_mutex.unlock(); - if (t) - t->deleteLater(); } QT_END_NAMESPACE diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h index c562a909c5..c1bf78a018 100644 --- a/src/quick/scenegraph/qsgcontext_p.h +++ b/src/quick/scenegraph/qsgcontext_p.h @@ -94,6 +94,7 @@ public: virtual void invalidate(); virtual void renderNextFrame(QSGRenderer *renderer, GLuint fboId); + virtual void endSync(); virtual QSharedPointer depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo); QSGDepthStencilBufferManager *depthStencilBufferManager(); @@ -124,6 +125,7 @@ protected: QMutex m_mutex; QHash m_textures; + QSet m_texturesToDelete; QSGAtlasTexture::Manager *m_atlasManager; QSGDepthStencilBufferManager *m_depthStencilManager; From fe6ad3ad4550c9efd2c07ca25ce3625c0615fcba Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Wed, 22 Jan 2014 15:32:56 +0100 Subject: [PATCH 17/26] Only look at alpha to decide if rectangle has fill or not. Task-number: QTBUG-35606 Change-Id: Id403047e19e75d91ec3b3f8367166d8ec96ecaf8 Reviewed-by: J-P Nurmi --- src/quick/scenegraph/qsgdefaultrectanglenode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp b/src/quick/scenegraph/qsgdefaultrectanglenode.cpp index fb989fd6fb..810a503cee 100644 --- a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp +++ b/src/quick/scenegraph/qsgdefaultrectanglenode.cpp @@ -385,7 +385,7 @@ void QSGDefaultRectangleNode::updateGeometry() int borderTail = 0; int outerAAHead = 0; int outerAATail = 0; - bool hasFill = m_color.rgba() != 0 || !stops.isEmpty(); + bool hasFill = m_color.alpha() > 0 || !stops.isEmpty(); if (hasFill) indexCount += fillIndexCount; if (m_antialiasing) { @@ -609,7 +609,7 @@ void QSGDefaultRectangleNode::updateGeometry() int borderTail = 0; int outerAAHead = 0; int outerAATail = 0; - bool hasFill = m_color.rgba() != 0 || !stops.isEmpty(); + bool hasFill = m_color.alpha() > 0 || !stops.isEmpty(); if (hasFill) indexCount += fillIndexCount; if (m_antialiasing) { From e8aaaaf3b9e4cf0fdf46ba1bce589d00259e0bad Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 21 Jan 2014 14:22:10 +0200 Subject: [PATCH 18/26] QQuickText: fix layout mirroring Task-number: QTBUG-35095 Change-Id: I8550821e01ecc931788c1ed73366ba1ceed7a817 Reviewed-by: Andrew den Exter --- src/quick/items/qquicktext.cpp | 8 ++++---- tests/auto/quick/qquicktext/tst_qquicktext.cpp | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index ad904a2579..038025856c 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -2070,7 +2070,7 @@ QRectF QQuickText::boundingRect() const Q_D(const QQuickText); QRectF rect = d->layedOutTextRect; - rect.moveLeft(QQuickTextUtil::alignedX(rect.width(), width(), d->hAlign)); + rect.moveLeft(QQuickTextUtil::alignedX(rect.width(), width(), effectiveHAlign())); rect.moveTop(QQuickTextUtil::alignedY(rect.height(), height(), d->vAlign)); if (d->style != Normal) @@ -2207,11 +2207,11 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data const QColor linkColor = QColor::fromRgba(d->linkColor); if (d->richText) { - const qreal dx = QQuickTextUtil::alignedX(d->layedOutTextRect.width(), width(), d->hAlign); + const qreal dx = QQuickTextUtil::alignedX(d->layedOutTextRect.width(), width(), effectiveHAlign()); d->ensureDoc(); node->addTextDocument(QPointF(dx, dy), d->extra->doc, color, d->style, styleColor, linkColor); } else if (d->layedOutTextRect.width() > 0) { - const qreal dx = QQuickTextUtil::alignedX(d->lineWidth, width(), d->hAlign); + const qreal dx = QQuickTextUtil::alignedX(d->lineWidth, width(), effectiveHAlign()); int unelidedLineCount = d->lineCount; if (d->elideLayout) unelidedLineCount -= 1; @@ -2483,7 +2483,7 @@ QString QQuickTextPrivate::anchorAt(const QPointF &mousePos) const link = anchorAt(elideLayout, translatedMousePos); return link; } else if (richText && extra.isAllocated() && extra->doc) { - translatedMousePos.rx() -= QQuickTextUtil::alignedX(layedOutTextRect.width(), q->width(), hAlign); + translatedMousePos.rx() -= QQuickTextUtil::alignedX(layedOutTextRect.width(), q->width(), q->effectiveHAlign()); return extra->doc->documentLayout()->anchorAt(translatedMousePos); } return QString(); diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp index 78e03be9c2..6a18323190 100644 --- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp @@ -1694,6 +1694,12 @@ void tst_qquicktext::linkInteraction_data() << (PointVector() << metrics.characterRectangle(18, Qt::AlignRight, Qt::AlignBottom).center()) << singleLineLink << singleLineLink << singleLineLink; + QTest::newRow("click on mirrored link") + << singleLineText << 240. + << "horizontalAlignment: Text.AlignLeft; LayoutMirroring.enabled: true" + << (PointVector() << metrics.characterRectangle(18, Qt::AlignRight, Qt::AlignTop).center()) + << singleLineLink + << singleLineLink << singleLineLink; QTest::newRow("click on center aligned link") << singleLineText << 240. << "horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter" @@ -2515,6 +2521,18 @@ void tst_qquicktext::boundingRect() QCOMPARE(text->boundingRect().width(), line.naturalTextWidth()); QCOMPARE(text->boundingRect().height(), line.height()); + QQuickItemPrivate::get(text)->setLayoutMirror(true); + QCOMPARE(text->boundingRect().x(), qreal(0)); + QCOMPARE(text->boundingRect().y(), qreal(0)); + QCOMPARE(text->boundingRect().width(), line.naturalTextWidth()); + QCOMPARE(text->boundingRect().height(), line.height()); + + text->setHAlign(QQuickText::AlignLeft); + QCOMPARE(text->boundingRect().x(), text->width() - line.naturalTextWidth()); + QCOMPARE(text->boundingRect().y(), qreal(0)); + QCOMPARE(text->boundingRect().width(), line.naturalTextWidth()); + QCOMPARE(text->boundingRect().height(), line.height()); + text->setWrapMode(QQuickText::Wrap); QCOMPARE(text->boundingRect().right(), text->width()); QCOMPARE(text->boundingRect().y(), qreal(0)); From 8933268baca5d1c2992c808a6399982f28babd47 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 22 Jan 2014 13:02:09 +0100 Subject: [PATCH 19/26] V4: remove more superfluous spills. Spills for targets of phi-nodes are already inserted by the renumbering, so they don't need to be added (again) while resolving edges. This fixes a problem with crypto.js. Change-Id: I4b1d79fc92236b4a6b0b6d6d30ada17c8581a093 Reviewed-by: Fawzi Mohamed Reviewed-by: Lars Knoll --- src/qml/compiler/qv4regalloc.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp index 3521d0c27a..49b7529b9d 100644 --- a/src/qml/compiler/qv4regalloc.cpp +++ b/src/qml/compiler/qv4regalloc.cpp @@ -956,9 +956,6 @@ private: moveTo = createTemp(Temp::StackSlot, spillSlot, it->temp().type); } else { moveTo = createTemp(Temp::PhysicalRegister, platformRegister(*it), it->temp().type); - const int spillSlot = _assignedSpillSlots.value(it->temp(), -1); - if (isPhiTarget && spillSlot != -1) - mapping.add(moveFrom, createTemp(Temp::StackSlot, spillSlot, it->temp().type)); } // add move to mapping From e7cf8b10ff9e8d70f90c2f27df60f9e040be6911 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 22 Jan 2014 13:02:33 -0800 Subject: [PATCH 20/26] Update changelog for 5.2.1 Change-Id: I6e8d2dbf129092c53331c639a767ca4955212f77 Reviewed-by: Simon Hausmann --- dist/changes-5.2.1 | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 dist/changes-5.2.1 diff --git a/dist/changes-5.2.1 b/dist/changes-5.2.1 new file mode 100644 index 0000000000..c5371185f0 --- /dev/null +++ b/dist/changes-5.2.1 @@ -0,0 +1,38 @@ +Qt 5.2.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.2.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + + http://qt-project.org/doc/qt-5.2 + +The Qt version 5.2 series is binary compatible with the 5.1.x series. +Applications compiled for 5.1 will continue to run with 5.2. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + + http://bugreports.qt-project.org/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Library * +**************************************************************************** + +QtQml +----- + + - [QTBUG-35979] Fixed JavaScript Array.pop() not updating the + internal array length correctly + +QtQuick +------- + + - [QTBUG-35128] Fixed TextInput to call fixup() on its validator when + being accepted or losing focus, and the validator reports that the input + is in "intermediate" state ie. the input should be fixed up. + - [QTBUG-34517] Fixed an issue that caused QQuickTextInput to not + accept delete/home/backspace/left/right keys when the key was used + in a shortcut. From f628067b9efe86766764ef47b4e50fee942ba1d8 Mon Sep 17 00:00:00 2001 From: Daniel Pesch Date: Wed, 22 Jan 2014 19:19:54 +0100 Subject: [PATCH 21/26] Qmlplugindump error messages are not written consistently For errors in command line parameters qmplugindump uses cerr but errors during plugin loading are logged using qWarning(). It would be better to log always to cerr in case of problem because some platforms (BB10) have logging from Qt redirected. Task-number: QTBUG-36378 Change-Id: I04506c2f12b87190966e66c482f4ac5aed44af05 Signed-off-by: Daniel Pesch Reviewed-by: Fawzi Mohamed --- tools/qmlplugindump/main.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp index 000af0a1d8..d53005109e 100644 --- a/tools/qmlplugindump/main.cpp +++ b/tools/qmlplugindump/main.cpp @@ -98,14 +98,14 @@ void collectReachableMetaObjects(QObject *object, QSet *met const QMetaObject *meta = object->metaObject(); if (verbose) - qDebug() << "Processing object" << meta->className(); + std::cerr << "Processing object" << qPrintable( meta->className() ) << std::endl; collectReachableMetaObjects(meta, metas); for (int index = 0; index < meta->propertyCount(); ++index) { QMetaProperty prop = meta->property(index); if (QQmlMetaType::isQObject(prop.userType())) { if (verbose) - qDebug() << " Processing property" << prop.name(); + std::cerr << " Processing property" << qPrintable( prop.name() ) << std::endl; currentProperty = QString("%1::%2").arg(meta->className(), prop.name()); // if the property was not initialized during construction, @@ -175,7 +175,7 @@ QByteArray convertToId(const QMetaObject *mo) if (!className.isEmpty()) return className; - qWarning() << "Found a QMetaObject without a className, generating a random name"; + std::cerr << "Found a QMetaObject without a className, generating a random name" << std::endl; className = QByteArray("error-unknown-name-"); className.append(QByteArray::number(generatedNames.size())); generatedNames.insert(mo, className); @@ -276,15 +276,15 @@ QSet collectReachableMetaObjects(QQmlEngine *engine, if (ty->isSingleton()) { QQmlType::SingletonInstanceInfo *siinfo = ty->singletonInstanceInfo(); if (!siinfo) { - qWarning() << "Internal error, " << tyName - << "(" << QString::fromUtf8(ty->typeName()) << ")" - << " is singleton, but has no singletonInstanceInfo"; + std::cerr << "Internal error, " << qPrintable(tyName) + << "(" << qPrintable( QString::fromUtf8(ty->typeName()) ) << ")" + << " is singleton, but has no singletonInstanceInfo" << std::endl; continue; } if (siinfo->qobjectCallback) { if (verbose) - qDebug() << "Trying to get singleton for " << tyName - << " (" << siinfo->typeName << ")"; + std::cerr << "Trying to get singleton for " << qPrintable(tyName) + << " (" << qPrintable( siinfo->typeName ) << ")" << std::endl; siinfo->init(engine); collectReachableMetaObjects(object, &metas); object = siinfo->qobjectApi(engine); @@ -294,8 +294,8 @@ QSet collectReachableMetaObjects(QQmlEngine *engine, } } else { if (verbose) - qDebug() << "Trying to create object " << tyName - << " (" << QString::fromUtf8(ty->typeName()) << ")"; + std::cerr << "Trying to create object " << qPrintable( tyName ) + << " (" << qPrintable( QString::fromUtf8(ty->typeName()) ) << ")" << std::endl; object = ty->create(); } @@ -303,11 +303,11 @@ QSet collectReachableMetaObjects(QQmlEngine *engine, if (object) { if (verbose) - qDebug() << "Got " << tyName - << " (" << QString::fromUtf8(ty->typeName()) << ")"; + std::cerr << "Got " << qPrintable( tyName ) + << " (" << qPrintable( QString::fromUtf8(ty->typeName()) ) << ")" << std::endl; collectReachableMetaObjects(object, &metas); } else { - qWarning() << "Could not create" << tyName; + std::cerr << "Could not create" << qPrintable(tyName) << std::endl; } } } @@ -807,7 +807,7 @@ int main(int argc, char *argv[]) c.create(); if (!c.errors().isEmpty()) { foreach (const QQmlError &error, c.errors()) - qWarning() << error.toString(); + std::cerr << qPrintable( error.toString() ) << std::endl; return EXIT_IMPORTERROR; } } @@ -833,7 +833,7 @@ int main(int argc, char *argv[]) QByteArray importCode; QQmlType *qtObjectType = QQmlMetaType::qmlType(&QObject::staticMetaObject); if (!qtObjectType) { - qWarning() << "Could not find QtObject type"; + std::cerr << "Could not find QtObject type" << std::endl; importCode = QByteArray("import QtQuick 2.0\n"); } else { QString module = qtObjectType->qmlTypeName(); @@ -862,7 +862,7 @@ int main(int argc, char *argv[]) c.create(); if (!c.errors().isEmpty()) { foreach (const QQmlError &error, c.errors()) - qWarning() << error.toString(); + std::cerr << qPrintable( error.toString() ) << std::endl; return EXIT_IMPORTERROR; } } From 898c8c76d23ba053d45296a5da4863a7e9e42bdd Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 23 Jan 2014 10:22:10 +0100 Subject: [PATCH 22/26] Fix warning about comparing double to boolean in js_equal(). jsapi\qjsvalue.cpp(749) : warning C4805: '==' : unsafe mix of type 'double' and type 'bool' in operation Change-Id: I06d0950ce932ea635c422d3fb42ca80e6725dda1 Reviewed-by: Lars Knoll --- src/qml/jsapi/qjsvalue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp index 6a0cf0cf6d..4cc3796541 100644 --- a/src/qml/jsapi/qjsvalue.cpp +++ b/src/qml/jsapi/qjsvalue.cpp @@ -746,7 +746,7 @@ static bool js_equal(const QString &string, QV4::ValueRef value) if (value->isNumber()) return __qmljs_string_to_number(string) == value->asDouble(); if (value->isBoolean()) - return __qmljs_string_to_number(string) == value->booleanValue(); + return __qmljs_string_to_number(string) == double(value->booleanValue()); if (value->isObject()) { Scope scope(value->objectValue()->engine()); ScopedValue p(scope, __qmljs_to_primitive(value, PREFERREDTYPE_HINT)); From 9262f8f1d66c44bd48080a1ecf961d5e28f455eb Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 22 Jan 2014 12:38:31 +0100 Subject: [PATCH 23/26] Fix compile error with clang 3.4 Change-Id: Iaf43f0527142bb5615e8c97bb1a80faf7b8b2e00 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlmetatype.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 37f26a236f..d1ab50c4af 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -664,7 +664,7 @@ void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const { // Add any enum values defined by 'related' classes if (metaObject->d.relatedMetaObjects) { - const QMetaObject **related = metaObject->d.relatedMetaObjects; + const QMetaObject * const *related = metaObject->d.relatedMetaObjects; if (related) { while (*related) insertEnums(*related++); From beffe565e3511bdd01a967303066a5dce88022f4 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Fri, 17 Jan 2014 16:13:08 +0100 Subject: [PATCH 24/26] V4: fix life-time hole check. This check was incorrect when a jump happened from before (or after) the life-time interval into a life-time hole. Change-Id: Idacf304a96d39f372249a48e18b00891531d9859 Reviewed-by: Lars Knoll --- src/qml/compiler/qv4regalloc.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp index 048aad8497..b80e5d3ee8 100644 --- a/src/qml/compiler/qv4regalloc.cpp +++ b/src/qml/compiler/qv4regalloc.cpp @@ -857,7 +857,6 @@ private: if (it->end() < successorStart) continue; - bool lifeTimeHole = false; bool isPhiTarget = false; Expr *moveFrom = 0; @@ -903,9 +902,7 @@ private: predIt->temp().type); } else { int spillSlot = _assignedSpillSlots.value(predIt->temp(), -1); - if (spillSlot == -1) - lifeTimeHole = true; - else + if (spillSlot != -1) moveFrom = createTemp(Temp::StackSlot, spillSlot, predIt->temp().type); } break; @@ -913,9 +910,11 @@ private: } } if (!moveFrom) { -#if defined(QT_NO_DEBUG) - Q_UNUSED(lifeTimeHole); -#else +#if !defined(QT_NO_DEBUG) + bool lifeTimeHole = false; + if (it->ranges().first().start <= successorStart && it->ranges().last().end >= successorStart) + lifeTimeHole = !it->covers(successorStart); + Q_ASSERT(!_info->isPhiTarget(it->temp()) || it->isSplitFromInterval() || lifeTimeHole); if (_info->def(it->temp()) != successorStart && !it->isSplitFromInterval()) { const int successorEnd = successor->statements.last()->id; From f27184dcb319748417181babe6fe03d659d6a515 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 24 Jan 2014 10:01:55 +0100 Subject: [PATCH 25/26] Don't write into the callers stack frame Never usee addressForArgument when arguments are passed in registers, as it points into the callers stack frame. The address was used as a temporary location when encoding a unsigned return value. The code has now been rewritten to only use registers instead. Change-Id: Id85b668a5a74dbd6c41621a9672e53a1cb5f242b Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4isel_masm.cpp | 19 ++++++++++++++----- src/qml/compiler/qv4isel_masm_p.h | 2 ++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp index 35097bae49..0cfb684e93 100644 --- a/src/qml/compiler/qv4isel_masm.cpp +++ b/src/qml/compiler/qv4isel_masm.cpp @@ -1957,12 +1957,21 @@ void InstructionSelection::visitRet(V4IR::Ret *s) Assembler::ScratchRegister); _as->xor64(Assembler::ScratchRegister, Assembler::ReturnValueRegister); } else if (t->type == V4IR::UInt32Type) { - Address tmp = addressForArgument(0); - _as->storeUInt32((Assembler::RegisterID) t->index, Pointer(tmp)); - _as->load64(tmp, Assembler::ReturnValueRegister); + Assembler::RegisterID srcReg = (Assembler::RegisterID) t->index; + Assembler::Jump intRange = _as->branch32(Assembler::GreaterThanOrEqual, srcReg, Assembler::TrustedImm32(0)); + _as->convertUInt32ToDouble(srcReg, Assembler::FPGpr0, Assembler::ReturnValueRegister); + _as->moveDoubleTo64(Assembler::FPGpr0, Assembler::ReturnValueRegister); + _as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask), Assembler::ScratchRegister); + _as->xor64(Assembler::ScratchRegister, Assembler::ReturnValueRegister); + Assembler::Jump done = _as->jump(); + intRange.link(_as); + _as->zeroExtend32ToPtr(srcReg, Assembler::ReturnValueRegister); + quint64 tag = QV4::Value::_Integer_Type; + _as->or64(Assembler::TrustedImm64(tag << 32), + Assembler::ReturnValueRegister); + done.link(_as); } else { - _as->zeroExtend32ToPtr((Assembler::RegisterID) t->index, - Assembler::ReturnValueRegister); + _as->zeroExtend32ToPtr((Assembler::RegisterID) t->index, Assembler::ReturnValueRegister); quint64 tag; switch (t->type) { case V4IR::SInt32Type: diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h index f5d4e469e5..a146220015 100644 --- a/src/qml/compiler/qv4isel_masm_p.h +++ b/src/qml/compiler/qv4isel_masm_p.h @@ -1481,6 +1481,7 @@ protected: typedef Assembler::Address Address; typedef Assembler::Pointer Pointer; +#if !defined(ARGUMENTS_IN_REGISTERS) Address addressForArgument(int index) const { // StackFrameRegister points to its old value on the stack, and above @@ -1488,6 +1489,7 @@ protected: // values before reaching the first argument. return Address(Assembler::StackFrameRegister, (index + 2) * sizeof(void*)); } +#endif Pointer baseAddressForCallArguments() { From 2407cd29e628671f7f5144e0d241d4249a3ab612 Mon Sep 17 00:00:00 2001 From: Jorgen Lind Date: Thu, 23 Jan 2014 12:22:43 +0100 Subject: [PATCH 26/26] Dont define CAN_BACKTRACE_EXECINFO when building on uClibc Change-Id: I06314f0a3a7cf86e5e627c307a522069cf640f78 Reviewed-by: Gunnar Sletta --- src/quick/scenegraph/util/qsgtexture.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp index 04ffad7acf..bfa0eaf920 100644 --- a/src/quick/scenegraph/util/qsgtexture.cpp +++ b/src/quick/scenegraph/util/qsgtexture.cpp @@ -50,7 +50,7 @@ #include #include -#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) +#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) && !defined(__UCLIBC__) #define CAN_BACKTRACE_EXECINFO #endif