aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@theqtcompany.com>2015-10-22 13:07:11 +0200
committerUlf Hermann <ulf.hermann@theqtcompany.com>2015-10-22 13:07:11 +0200
commitb103f6a6b9cc0ddf3df2788816a6fd98369b1b6d (patch)
treefc90bc070f0f50a2d8768db8fa1e16611d158f18 /src
parent4867a49618e0d6a476e0549aeca5134b2e3c5892 (diff)
parent8ee3673e439b4499a8a4a4280637ee0270c4a54a (diff)
Merge remote-tracking branch 'origin/5.6' into origin/dev
Conflicts: src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h src/qml/debugger/qqmldebugserviceinterfaces.cpp src/qml/jsruntime/qv4debugging_p.h Change-Id: I82a4ce1bcd4579181df886558f55ad2b328d1682
Diffstat (limited to 'src')
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro2
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservice.json2
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp4
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp804
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.h92
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp4
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h14
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp46
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h13
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp59
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h6
-rw-r--r--src/plugins/qmltooling/qmldbg_native/qmldbg_native.pro12
-rw-r--r--src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.cpp384
-rw-r--r--src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.json3
-rw-r--r--src/plugins/qmltooling/qmltooling.pro1
-rw-r--r--src/qml/compiler/qv4ssa.cpp141
-rw-r--r--src/qml/debugger/qqmldebugconnector.cpp15
-rw-r--r--src/qml/debugger/qqmldebugpluginmanager_p.h6
-rw-r--r--src/qml/debugger/qqmldebugserviceinterfaces.cpp1
-rw-r--r--src/qml/debugger/qqmldebugserviceinterfaces_p.h13
-rw-r--r--src/qml/doc/qtqml.qdocconf2
-rw-r--r--src/qml/doc/snippets/qml/qtBinding.2.qml2
-rw-r--r--src/qml/doc/src/javascript/hostenvironment.qdoc2
-rw-r--r--src/qml/doc/src/javascript/resources.qdoc14
-rw-r--r--src/qml/jsruntime/qv4context.cpp17
-rw-r--r--src/qml/jsruntime/qv4debugging.cpp48
-rw-r--r--src/qml/jsruntime/qv4debugging_p.h19
-rw-r--r--src/qml/jsruntime/qv4engine.cpp5
-rw-r--r--src/qml/jsruntime/qv4engine_p.h2
-rw-r--r--src/qml/jsruntime/qv4mathobject.cpp9
-rw-r--r--src/qml/jsruntime/qv4object.cpp2
-rw-r--r--src/qml/qml/qqmlmetatype.cpp7
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h3
-rw-r--r--src/qml/types/qqmlinstantiator.cpp4
-rw-r--r--src/qml/types/qqmlitemmodels.qdoc40
-rw-r--r--src/quick/accessible/qaccessiblequickitem.cpp9
-rw-r--r--src/quick/doc/qtquick.qdocconf2
-rw-r--r--src/quick/doc/src/concepts/effects/sprites.qdoc7
-rw-r--r--src/quick/doc/src/concepts/effects/transformations.qdoc2
-rw-r--r--src/quick/doc/src/concepts/input/textinput.qdoc7
-rw-r--r--src/quick/doc/src/concepts/positioning/layouts.qdoc3
-rw-r--r--src/quick/doc/src/concepts/statesanimations/animations.qdoc24
-rw-r--r--src/quick/doc/src/concepts/statesanimations/states.qdoc3
-rw-r--r--src/quick/items/qquickitem.cpp33
-rw-r--r--src/quick/items/qquickitem_p.h4
-rw-r--r--src/quick/items/qquickwindow.cpp3
-rw-r--r--src/quick/scenegraph/coreapi/qsgnodeupdater.cpp18
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp3
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp3
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp3
-rw-r--r--src/quick/util/qquickanimation.cpp16
-rw-r--r--src/quick/util/qquickfontmetrics.cpp3
-rw-r--r--src/quick/util/qquicktextmetrics.cpp2
-rw-r--r--src/quick/util/qquicktransition.cpp2
54 files changed, 1683 insertions, 262 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro
index d860328dc8..8d1a54e9e4 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro
+++ b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro
@@ -9,6 +9,7 @@ SOURCES += \
$$PWD/qdebugmessageservice.cpp \
$$PWD/qqmldebuggerservicefactory.cpp \
$$PWD/qqmlenginedebugservice.cpp \
+ $$PWD/qqmlnativedebugservice.cpp \
$$PWD/qqmlwatcher.cpp \
$$PWD/qv4debugservice.cpp \
$$PWD/qv4debuggeragent.cpp \
@@ -19,6 +20,7 @@ HEADERS += \
$$PWD/qdebugmessageservice.h \
$$PWD/qqmldebuggerservicefactory.h \
$$PWD/qqmlenginedebugservice.h \
+ $$PWD/qqmlnativedebugservice.h \
$$PWD/qqmlwatcher.h \
$$PWD/qv4debugservice.h \
$$PWD/qv4debuggeragent.h \
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservice.json b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservice.json
index b1e90364d5..967a725903 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservice.json
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservice.json
@@ -1,3 +1,3 @@
{
- "Keys": [ "DebugMessages", "QmlDebugger", "V8Debugger" ]
+ "Keys": [ "DebugMessages", "QmlDebugger", "V8Debugger", "NativeQmlDebugger" ]
}
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp
index ac3b435350..4690da04d1 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp
@@ -35,6 +35,7 @@
#include "qqmlenginedebugservice.h"
#include "qdebugmessageservice.h"
#include "qv4debugservice.h"
+#include "qqmlnativedebugservice.h"
#include <private/qqmldebugserviceinterfaces_p.h>
QT_BEGIN_NAMESPACE
@@ -50,6 +51,9 @@ QQmlDebugService *QQmlDebuggerServiceFactory::create(const QString &key)
if (key == QV4DebugServiceImpl::s_key)
return new QV4DebugServiceImpl(this);
+ if (key == QQmlNativeDebugServiceImpl::s_key)
+ return new QQmlNativeDebugServiceImpl(this);
+
return 0;
}
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp
new file mode 100644
index 0000000000..f5cc78e77f
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp
@@ -0,0 +1,804 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlnativedebugservice.h"
+
+#include <private/qqmldebugconnector_p.h>
+#include <private/qv4debugging_p.h>
+#include <private/qv8engine_p.h>
+#include <private/qv4engine_p.h>
+#include <private/qv4debugging_p.h>
+#include <private/qv4script_p.h>
+#include <private/qv4string_p.h>
+#include <private/qv4objectiterator_p.h>
+#include <private/qv4identifier_p.h>
+#include <private/qv4runtime_p.h>
+#include <private/qv4isel_moth_p.h>
+#include <private/qqmldebugserviceinterfaces_p.h>
+
+#include <qqmlengine.h>
+
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qjsondocument.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qjsonvalue.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qpointer.h>
+
+//#define TRACE_PROTOCOL(s) qDebug() << s
+#define TRACE_PROTOCOL(s)
+
+QT_BEGIN_NAMESPACE
+
+class BreakPoint
+{
+public:
+ BreakPoint() : id(-1), lineNumber(-1), enabled(false), ignoreCount(0), hitCount(0) {}
+ bool isValid() const { return lineNumber >= 0 && !fileName.isEmpty(); }
+
+ int id;
+ int lineNumber;
+ QString fileName;
+ bool enabled;
+ QString condition;
+ int ignoreCount;
+
+ int hitCount;
+};
+
+inline uint qHash(const BreakPoint &b, uint seed = 0) Q_DECL_NOTHROW
+{
+ return qHash(b.fileName, seed) ^ b.lineNumber;
+}
+
+inline bool operator==(const BreakPoint &a, const BreakPoint &b)
+{
+ return a.lineNumber == b.lineNumber && a.fileName == b.fileName
+ && a.enabled == b.enabled && a.condition == b.condition
+ && a.ignoreCount == b.ignoreCount;
+}
+
+static void setError(QJsonObject *response, const QString &msg)
+{
+ response->insert(QStringLiteral("type"), QStringLiteral("error"));
+ response->insert(QStringLiteral("msg"), msg);
+}
+
+class NativeDebugger;
+
+class Collector
+{
+public:
+ Collector(QV4::ExecutionEngine *engine)
+ : m_engine(engine), m_anonCount(0)
+ {}
+
+ void collect(QJsonArray *output, const QString &parentIName, const QString &name,
+ const QV4::Value &value);
+
+ bool isExpanded(const QString &iname) const { return m_expanded.contains(iname); }
+
+public:
+ QV4::ExecutionEngine *m_engine;
+ int m_anonCount;
+ QStringList m_expanded;
+};
+
+// Encapsulate Breakpoint handling
+// Could be made per-NativeDebugger (i.e. per execution engine, if needed)
+class BreakPointHandler
+{
+public:
+ BreakPointHandler() : m_haveBreakPoints(false), m_breakOnThrow(true), m_lastBreakpoint(1) {}
+
+ void handleSetBreakpoint(QJsonObject *response, const QJsonObject &arguments);
+ void handleRemoveBreakpoint(QJsonObject *response, const QJsonObject &arguments);
+
+ void removeBreakPoint(int id);
+ void enableBreakPoint(int id, bool onoff);
+
+ void setBreakOnThrow(bool onoff);
+ bool m_haveBreakPoints;
+ bool m_breakOnThrow;
+ int m_lastBreakpoint;
+ QVector<BreakPoint> m_breakPoints;
+};
+
+void BreakPointHandler::handleSetBreakpoint(QJsonObject *response, const QJsonObject &arguments)
+{
+ TRACE_PROTOCOL("SET BREAKPOINT" << arguments);
+ QString type = arguments.value(QStringLiteral("type")).toString();
+
+ QString fileName = arguments.value(QStringLiteral("file")).toString();
+ if (fileName.isEmpty()) {
+ setError(response, QStringLiteral("breakpoint has no file name"));
+ return;
+ }
+
+ int line = arguments.value(QStringLiteral("line")).toInt(-1);
+ if (line < 0) {
+ setError(response, QStringLiteral("breakpoint has an invalid line number"));
+ return;
+ }
+
+ BreakPoint bp;
+ bp.id = m_lastBreakpoint++;
+ bp.fileName = fileName.mid(fileName.lastIndexOf('/') + 1);
+ bp.lineNumber = line;
+ bp.enabled = arguments.value(QStringLiteral("enabled")).toBool(true);
+ bp.condition = arguments.value(QStringLiteral("condition")).toString();
+ bp.ignoreCount = arguments.value(QStringLiteral("ignorecount")).toInt();
+ m_breakPoints.append(bp);
+
+ m_haveBreakPoints = true;
+
+ response->insert(QStringLiteral("type"), type);
+ response->insert(QStringLiteral("breakpoint"), bp.id);
+}
+
+void BreakPointHandler::handleRemoveBreakpoint(QJsonObject *response, const QJsonObject &arguments)
+{
+ int id = arguments.value(QStringLiteral("id")).toInt();
+ removeBreakPoint(id);
+ response->insert(QStringLiteral("id"), id);
+}
+
+class NativeDebugger : public QV4::Debugging::Debugger
+{
+public:
+ NativeDebugger(QQmlNativeDebugServiceImpl *service, QV4::ExecutionEngine *engine);
+
+ void signalEmitted(const QString &signal);
+
+ QV4::ExecutionEngine *engine() const { return m_engine; }
+
+ bool pauseAtNextOpportunity() const Q_DECL_OVERRIDE {
+ return m_pauseRequested
+ || m_service->m_breakHandler->m_haveBreakPoints
+ || m_stepping >= StepOver;
+ }
+
+ void maybeBreakAtInstruction() Q_DECL_OVERRIDE;
+ void enteringFunction() Q_DECL_OVERRIDE;
+ void leavingFunction(const QV4::ReturnedValue &retVal) Q_DECL_OVERRIDE;
+ void aboutToThrow() Q_DECL_OVERRIDE;
+
+ void handleCommand(QJsonObject *response, const QString &cmd, const QJsonObject &arguments);
+
+private:
+ void handleBacktrace(QJsonObject *response, const QJsonObject &arguments);
+ void handleVariables(QJsonObject *response, const QJsonObject &arguments);
+ void handleExpressions(QJsonObject *response, const QJsonObject &arguments);
+
+ void handleDebuggerDeleted(QObject *debugger);
+
+ QV4::ReturnedValue evaluateExpression(QV4::Scope &scope, const QString &expression);
+ bool checkCondition(const QString &expression);
+
+ QStringList breakOnSignals;
+
+ enum Speed {
+ NotStepping = 0,
+ StepOut,
+ StepOver,
+ StepIn,
+ };
+
+ void pauseAndWait();
+ void pause();
+ void handleContinue(QJsonObject *reponse, Speed speed);
+
+ QV4::Function *getFunction() const;
+
+ bool reallyHitTheBreakPoint(const QV4::Function *function, int lineNumber);
+
+ QV4::ExecutionEngine *m_engine;
+ QQmlNativeDebugServiceImpl *m_service;
+ QV4::PersistentValue m_currentContext;
+ Speed m_stepping;
+ bool m_pauseRequested;
+ bool m_runningJob;
+
+ QV4::PersistentValue m_returnedValue;
+};
+
+bool NativeDebugger::checkCondition(const QString &expression)
+{
+ QV4::Scope scope(m_engine);
+ QV4::ReturnedValue result = evaluateExpression(scope, expression);
+ QV4::ScopedValue val(scope, result);
+ return val->booleanValue();
+}
+
+QV4::ReturnedValue NativeDebugger::evaluateExpression(QV4::Scope &scope, const QString &expression)
+{
+ m_runningJob = true;
+
+ QV4::ExecutionContextSaver saver(scope);
+
+ QV4::ExecutionContext *ctx = m_engine->currentContext;
+ m_engine->pushContext(ctx);
+
+ QV4::Script script(ctx, expression);
+ script.strictMode = ctx->d()->strictMode;
+ // In order for property lookups in QML to work, we need to disable fast v4 lookups.
+ // That is a side-effect of inheritContext.
+ script.inheritContext = true;
+ script.parse();
+ QV4::ScopedValue result(scope);
+ if (!m_engine->hasException)
+ result = script.run();
+
+ m_runningJob = false;
+ return result->asReturnedValue();
+}
+
+NativeDebugger::NativeDebugger(QQmlNativeDebugServiceImpl *service, QV4::ExecutionEngine *engine)
+ : m_returnedValue(engine, QV4::Primitive::undefinedValue())
+{
+ m_stepping = NotStepping;
+ m_pauseRequested = false;
+ m_runningJob = false;
+ m_service = service;
+ m_engine = engine;
+ TRACE_PROTOCOL("Creating native debugger");
+}
+
+void NativeDebugger::signalEmitted(const QString &signal)
+{
+ //This function is only called by QQmlBoundSignal
+ //only if there is a slot connected to the signal. Hence, there
+ //is no need for additional check.
+
+ //Parse just the name and remove the class info
+ //Normalize to Lower case.
+ QString signalName = signal.left(signal.indexOf(QLatin1Char('('))).toLower();
+
+ foreach (const QString &signal, breakOnSignals) {
+ if (signal == signalName) {
+ // TODO: pause debugger
+ break;
+ }
+ }
+}
+
+void NativeDebugger::handleCommand(QJsonObject *response, const QString &cmd,
+ const QJsonObject &arguments)
+{
+ if (cmd == QStringLiteral("backtrace"))
+ handleBacktrace(response, arguments);
+ else if (cmd == QStringLiteral("variables"))
+ handleVariables(response, arguments);
+ else if (cmd == QStringLiteral("expressions"))
+ handleExpressions(response, arguments);
+ else if (cmd == QStringLiteral("stepin"))
+ handleContinue(response, StepIn);
+ else if (cmd == QStringLiteral("stepout"))
+ handleContinue(response, StepOut);
+ else if (cmd == QStringLiteral("stepover"))
+ handleContinue(response, StepOver);
+ else if (cmd == QStringLiteral("continue"))
+ handleContinue(response, NotStepping);
+}
+
+static QString encodeContext(QV4::ExecutionContext *executionContext)
+{
+ QByteArray ba;
+ QDataStream ds(&ba, QIODevice::WriteOnly);
+ ds << quintptr(executionContext);
+ return QString::fromLatin1(ba.toHex());
+}
+
+static void decodeContext(const QString &context, QV4::ExecutionContext **executionContext)
+{
+ quintptr rawContext;
+ QDataStream ds(QByteArray::fromHex(context.toLatin1()));
+ ds >> rawContext;
+ *executionContext = reinterpret_cast<QV4::ExecutionContext *>(rawContext);
+}
+
+void NativeDebugger::handleBacktrace(QJsonObject *response, const QJsonObject &arguments)
+{
+ int limit = arguments.value(QStringLiteral("limit")).toInt(0);
+
+ QJsonArray frameArray;
+ QV4::ExecutionContext *executionContext = m_engine->currentContext;
+ for (int i = 0; i < limit && executionContext; ++i) {
+ QV4::Heap::FunctionObject *heapFunctionObject = executionContext->getFunctionObject();
+ if (heapFunctionObject) {
+
+ QJsonObject frame;
+ frame[QStringLiteral("language")] = QStringLiteral("js");
+ frame[QStringLiteral("context")] = encodeContext(executionContext);
+
+ if (QV4::Function *function = heapFunctionObject->function) {
+ if (QV4::Heap::String *functionName = function->name())
+ frame[QStringLiteral("function")] = functionName->toQString();
+ frame[QStringLiteral("file")] = function->sourceFile();
+ }
+ int line = executionContext->d()->lineNumber;
+ frame[QStringLiteral("line")] = (line < 0 ? -line : line);
+
+ frameArray.push_back(frame);
+ }
+
+ executionContext = m_engine->parentContext(executionContext);
+ }
+
+ response->insert(QStringLiteral("frames"), frameArray);
+}
+
+void Collector::collect(QJsonArray *out, const QString &parentIName, const QString &name,
+ const QV4::Value &value)
+{
+ QJsonObject dict;
+ QV4::Scope scope(m_engine);
+
+ QString nonEmptyName = name.isEmpty() ? QString::fromLatin1("@%1").arg(m_anonCount++) : name;
+ QString iname = parentIName + QLatin1Char('.') + nonEmptyName;
+ dict.insert(QStringLiteral("iname"), iname);
+ dict.insert(QStringLiteral("name"), nonEmptyName);
+
+ QV4::ScopedValue typeString(scope, QV4::Runtime::typeofValue(m_engine, value));
+ dict.insert(QStringLiteral("type"), typeString->toQStringNoThrow());
+
+ switch (value.type()) {
+ case QV4::Value::Empty_Type:
+ dict.insert(QStringLiteral("valueencoded"), QStringLiteral("empty"));
+ dict.insert(QStringLiteral("haschild"), false);
+ break;
+ case QV4::Value::Undefined_Type:
+ dict.insert(QStringLiteral("valueencoded"), QStringLiteral("undefined"));
+ dict.insert(QStringLiteral("haschild"), false);
+ break;
+ case QV4::Value::Null_Type:
+ dict.insert(QStringLiteral("type"), QStringLiteral("object"));
+ dict.insert(QStringLiteral("valueencoded"), QStringLiteral("null"));
+ dict.insert(QStringLiteral("haschild"), false);
+ break;
+ case QV4::Value::Boolean_Type:
+ dict.insert(QStringLiteral("value"), value.booleanValue());
+ dict.insert(QStringLiteral("haschild"), false);
+ break;
+ case QV4::Value::Managed_Type:
+ if (const QV4::String *string = value.as<QV4::String>()) {
+ dict.insert(QStringLiteral("value"), string->toQStringNoThrow());
+ dict.insert(QStringLiteral("haschild"), false);
+ dict.insert(QStringLiteral("valueencoded"), QStringLiteral("utf16"));
+ dict.insert(QStringLiteral("quoted"), true);
+ } else if (const QV4::ArrayObject *array = value.as<QV4::ArrayObject>()) {
+ // The size of an array is number of its numerical properties.
+ // We don't consider free form object properties here.
+ const uint n = array->getLength();
+ dict.insert(QStringLiteral("value"), qint64(n));
+ dict.insert(QStringLiteral("valueencoded"), QStringLiteral("itemcount"));
+ dict.insert(QStringLiteral("haschild"), qint64(n));
+ if (isExpanded(iname)) {
+ QJsonArray children;
+ for (uint i = 0; i < n; ++i) {
+ QV4::ReturnedValue v = array->getIndexed(i);
+ QV4::ScopedValue sval(scope, v);
+ collect(&children, iname, QString::number(i), *sval);
+ }
+ dict.insert(QStringLiteral("children"), children);
+ }
+ } else if (const QV4::Object *object = value.as<QV4::Object>()) {
+ QJsonArray children;
+ bool expanded = isExpanded(iname);
+ qint64 numProperties = 0;
+ QV4::ObjectIterator it(scope, object, QV4::ObjectIterator::EnumerableOnly);
+ QV4::ScopedProperty p(scope);
+ QV4::ScopedString name(scope);
+ while (true) {
+ QV4::PropertyAttributes attrs;
+ uint index;
+ it.next(name.getRef(), &index, p, &attrs);
+ if (attrs.isEmpty())
+ break;
+ if (name.getPointer()) {
+ ++numProperties;
+ if (expanded) {
+ if (name.getPointer()) {
+ QV4::Value v = p.property->value;
+ collect(&children, iname, name->toQStringNoThrow(), v);
+ }
+ }
+ }
+ }
+ dict.insert(QStringLiteral("value"), numProperties);
+ dict.insert(QStringLiteral("valueencoded"), QStringLiteral("itemcount"));
+ dict.insert(QStringLiteral("haschild"), numProperties > 0);
+ if (expanded)
+ dict.insert(QStringLiteral("children"), children);
+ }
+ break;
+ case QV4::Value::Integer_Type:
+ dict.insert(QStringLiteral("value"), value.integerValue());
+ dict.insert(QStringLiteral("haschild"), false);
+ break;
+ default: // double
+ dict.insert(QStringLiteral("value"), value.doubleValue());
+ dict.insert(QStringLiteral("haschild"), false);
+ }
+
+ out->append(dict);
+}
+
+void NativeDebugger::handleVariables(QJsonObject *response, const QJsonObject &arguments)
+{
+ TRACE_PROTOCOL("Build variables");
+ QV4::ExecutionContext *executionContext = 0;
+ decodeContext(arguments.value(QStringLiteral("context")).toString(), &executionContext);
+ if (!executionContext) {
+ setError(response, QStringLiteral("No execution context passed"));
+ return;
+ }
+ TRACE_PROTOCOL("Context: " << executionContext);
+
+ QV4::ExecutionEngine *engine = executionContext->d()->engine;
+ if (!engine) {
+ setError(response, QStringLiteral("No execution engine passed"));
+ return;
+ }
+ TRACE_PROTOCOL("Engine: " << engine);
+
+ Collector collector(engine);
+ QJsonArray expanded = arguments.value(QStringLiteral("expanded")).toArray();
+ foreach (const QJsonValue &ex, expanded)
+ collector.m_expanded.append(ex.toString());
+ TRACE_PROTOCOL("Expanded: " << collector.m_expanded);
+
+ QJsonArray output;
+ QV4::Scope scope(engine);
+
+ if (QV4::CallContext *callContext = executionContext->asCallContext()) {
+ QV4::Value thisObject = callContext->thisObject();
+ collector.collect(&output, QString(), QStringLiteral("this"), thisObject);
+ QV4::Identifier *const *variables = callContext->variables();
+ QV4::Identifier *const *formals = callContext->formals();
+ for (unsigned i = 0, ei = callContext->variableCount(); i != ei; ++i) {
+ QString qName;
+ if (QV4::Identifier *name = variables[i])
+ qName = name->string;
+ QV4::Value val = callContext->d()->locals[i];
+ collector.collect(&output, QString(), qName, val);
+ }
+ for (unsigned i = 0, ei = callContext->formalCount(); i != ei; ++i) {
+ QString qName;
+ if (QV4::Identifier *name = formals[i])
+ qName = name->string;
+ QV4::ReturnedValue rval = callContext->argument(i);
+ QV4::ScopedValue sval(scope, rval);
+ collector.collect(&output, QString(), qName, *sval);
+ }
+ }
+
+ response->insert(QStringLiteral("variables"), output);
+}
+
+void NativeDebugger::handleExpressions(QJsonObject *response, const QJsonObject &arguments)
+{
+ TRACE_PROTOCOL("Evaluate expressions");
+ QV4::ExecutionContext *executionContext = 0;
+ decodeContext(arguments.value(QStringLiteral("context")).toString(), &executionContext);
+ if (!executionContext) {
+ setError(response, QStringLiteral("No execution context passed"));
+ return;
+ }
+ TRACE_PROTOCOL("Context: " << executionContext);
+
+ QV4::ExecutionEngine *engine = executionContext->d()->engine;
+ if (!engine) {
+ setError(response, QStringLiteral("No execution engine passed"));
+ return;
+ }
+ TRACE_PROTOCOL("Engines: " << engine << m_engine);
+
+ Collector collector(engine);
+ QJsonArray expanded = arguments.value(QStringLiteral("expanded")).toArray();
+ foreach (const QJsonValue &ex, expanded)
+ collector.m_expanded.append(ex.toString());
+ TRACE_PROTOCOL("Expanded: " << collector.m_expanded);
+
+ QJsonArray output;
+ QV4::Scope scope(engine);
+
+ QJsonArray expressions = arguments.value(QStringLiteral("expressions")).toArray();
+ foreach (const QJsonValue &expr, expressions) {
+ QString expression = expr.toObject().value(QStringLiteral("expression")).toString();
+ QString name = expr.toObject().value(QStringLiteral("name")).toString();
+ TRACE_PROTOCOL("Evaluate expression: " << expression);
+ m_runningJob = true;
+
+ QV4::ReturnedValue eval = evaluateExpression(scope, expression);
+ QV4::ScopedValue result(scope, eval);
+
+ m_runningJob = false;
+ if (result->isUndefined()) {
+ QJsonObject dict;
+ dict[QStringLiteral("name")] = name;
+ dict[QStringLiteral("valueencoded")] = QStringLiteral("undefined");
+ output.append(dict);
+ } else if (result.ptr && result.ptr->_val) {
+ collector.collect(&output, QString(), name, *result);
+ } else {
+ QJsonObject dict;
+ dict[QStringLiteral("name")] = name;
+ dict[QStringLiteral("valueencoded")] = QStringLiteral("notaccessible");
+ output.append(dict);
+ }
+ TRACE_PROTOCOL("EXCEPTION: " << engine->hasException);
+ engine->hasException = false;
+ }
+
+ response->insert(QStringLiteral("expressions"), output);
+}
+
+void BreakPointHandler::removeBreakPoint(int id)
+{
+ for (int i = 0; i != m_breakPoints.size(); ++i) {
+ if (m_breakPoints.at(i).id == id) {
+ m_breakPoints.remove(i);
+ m_haveBreakPoints = !m_breakPoints.isEmpty();
+ return;
+ }
+ }
+}
+
+void BreakPointHandler::enableBreakPoint(int id, bool enabled)
+{
+ m_breakPoints[id].enabled = enabled;
+}
+
+void NativeDebugger::pause()
+{
+ m_pauseRequested = true;
+}
+
+void NativeDebugger::handleContinue(QJsonObject *response, Speed speed)
+{
+ Q_UNUSED(response);
+
+ if (!m_returnedValue.isUndefined())
+ m_returnedValue.set(m_engine, QV4::Encode::undefined());
+
+ m_currentContext.set(m_engine, *m_engine->currentContext);
+ m_stepping = speed;
+}
+
+void NativeDebugger::maybeBreakAtInstruction()
+{
+ if (m_runningJob) // do not re-enter when we're doing a job for the debugger.
+ return;
+
+ if (m_stepping == StepOver) {
+ if (m_currentContext.asManaged()->d() == m_engine->current)
+ pauseAndWait();
+ return;
+ }
+
+ if (m_stepping == StepIn) {
+ pauseAndWait();
+ return;
+ }
+
+ if (m_pauseRequested) { // Serve debugging requests from the agent
+ m_pauseRequested = false;
+ pauseAndWait();
+ return;
+ }
+
+ if (m_service->m_breakHandler->m_haveBreakPoints) {
+ if (QV4::Function *function = getFunction()) {
+ const int lineNumber = m_engine->current->lineNumber;
+ if (reallyHitTheBreakPoint(function, lineNumber))
+ pauseAndWait();
+ }
+ }
+}
+
+void NativeDebugger::enteringFunction()
+{
+ if (m_runningJob)
+ return;
+
+ if (m_stepping == StepIn) {
+ m_currentContext.set(m_engine, *m_engine->currentContext);
+ }
+}
+
+void NativeDebugger::leavingFunction(const QV4::ReturnedValue &retVal)
+{
+ if (m_runningJob)
+ return;
+
+ if (m_stepping != NotStepping && m_currentContext.asManaged()->d() == m_engine->current) {
+ m_currentContext.set(m_engine, *m_engine->parentContext(m_engine->currentContext));
+ m_stepping = StepOver;
+ m_returnedValue.set(m_engine, retVal);
+ }
+}
+
+void NativeDebugger::aboutToThrow()
+{
+ if (!m_service->m_breakHandler->m_breakOnThrow)
+ return;
+
+ if (m_runningJob) // do not re-enter when we're doing a job for the debugger.
+ return;
+
+ QJsonObject event;
+ // TODO: complete this!
+ event.insert(QStringLiteral("event"), QStringLiteral("exception"));
+ m_service->emitAsynchronousMessageToClient(event);
+}
+
+QV4::Function *NativeDebugger::getFunction() const
+{
+ QV4::Scope scope(m_engine);
+ QV4::ExecutionContext *context = m_engine->currentContext;
+ QV4::ScopedFunctionObject function(scope, context->getFunctionObject());
+ if (function)
+ return function->function();
+ else
+ return context->d()->engine->globalCode;
+}
+
+void NativeDebugger::pauseAndWait()
+{
+ QJsonObject event;
+
+ event.insert(QStringLiteral("event"), QStringLiteral("break"));
+ event.insert(QStringLiteral("language"), QStringLiteral("js"));
+ if (QV4::ExecutionContext *executionContext = m_engine->currentContext) {
+ QV4::Heap::FunctionObject *heapFunctionObject = executionContext->getFunctionObject();
+ if (heapFunctionObject) {
+ if (QV4::Function *function = heapFunctionObject->function)
+ event.insert(QStringLiteral("file"), function->sourceFile());
+ int line = executionContext->d()->lineNumber;
+ event.insert(QStringLiteral("line"), (line < 0 ? -line : line));
+ }
+ }
+
+ m_service->emitAsynchronousMessageToClient(event);
+}
+
+bool NativeDebugger::reallyHitTheBreakPoint(const QV4::Function *function, int lineNumber)
+{
+ for (int i = 0, n = m_service->m_breakHandler->m_breakPoints.size(); i != n; ++i) {
+ const BreakPoint &bp = m_service->m_breakHandler->m_breakPoints.at(i);
+ if (bp.lineNumber == lineNumber) {
+ const QString fileName = function->sourceFile();
+ const QString base = fileName.mid(fileName.lastIndexOf('/') + 1);
+ if (bp.fileName.endsWith(base)) {
+ if (bp.condition.isEmpty() || checkCondition(bp.condition)) {
+ BreakPoint &mbp = m_service->m_breakHandler->m_breakPoints[i];
+ ++mbp.hitCount;
+ if (mbp.hitCount > mbp.ignoreCount)
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+QQmlNativeDebugServiceImpl::QQmlNativeDebugServiceImpl(QObject *parent)
+ : QQmlNativeDebugService(1.0, parent)
+{
+ m_breakHandler = new BreakPointHandler;
+}
+
+QQmlNativeDebugServiceImpl::~QQmlNativeDebugServiceImpl()
+{
+ delete m_breakHandler;
+}
+
+void QQmlNativeDebugServiceImpl::engineAboutToBeAdded(QQmlEngine *engine)
+{
+ TRACE_PROTOCOL("Adding engine" << engine);
+ if (engine) {
+ QV4::ExecutionEngine *ee = QV8Engine::getV4(engine->handle());
+ TRACE_PROTOCOL("Adding execution engine" << ee);
+ if (ee) {
+ NativeDebugger *debugger = new NativeDebugger(this, ee);
+ ee->iselFactory.reset(new QV4::Moth::ISelFactory);
+ if (state() == Enabled)
+ ee->setDebugger(debugger);
+ m_debuggers.append(QPointer<NativeDebugger>(debugger));
+ }
+ }
+ QQmlDebugService::engineAboutToBeAdded(engine);
+}
+
+void QQmlNativeDebugServiceImpl::engineAboutToBeRemoved(QQmlEngine *engine)
+{
+ TRACE_PROTOCOL("Removing engine" << engine);
+ if (engine) {
+ QV4::ExecutionEngine *executionEngine = QV8Engine::getV4(engine->handle());
+ foreach (NativeDebugger *debugger, m_debuggers) {
+ if (debugger->engine() == executionEngine)
+ m_debuggers.removeAll(debugger);
+ }
+ }
+ QQmlDebugService::engineAboutToBeRemoved(engine);
+}
+
+void QQmlNativeDebugServiceImpl::stateAboutToBeChanged(QQmlDebugService::State state)
+{
+ if (state == Enabled) {
+ foreach (NativeDebugger *debugger, m_debuggers) {
+ QV4::ExecutionEngine *engine = debugger->engine();
+ if (!engine->debugger)
+ engine->setDebugger(debugger);
+ }
+ }
+ QQmlDebugService::stateAboutToBeChanged(state);
+}
+
+void QQmlNativeDebugServiceImpl::messageReceived(const QByteArray &message)
+{
+ TRACE_PROTOCOL("Native message received: " << message);
+ QJsonObject request = QJsonDocument::fromJson(message).object();
+ QJsonObject response;
+ QJsonObject arguments = request.value(QStringLiteral("arguments")).toObject();
+ QString cmd = request.value(QStringLiteral("command")).toString();
+
+ if (cmd == QStringLiteral("setbreakpoint")) {
+ m_breakHandler->handleSetBreakpoint(&response, arguments);
+ } else if (cmd == QStringLiteral("removebreakpoint")) {
+ m_breakHandler->handleRemoveBreakpoint(&response, arguments);
+ } else if (cmd == QStringLiteral("echo")) {
+ response.insert(QStringLiteral("result"), arguments);
+ } else {
+ foreach (NativeDebugger *debugger, m_debuggers)
+ if (debugger)
+ debugger->handleCommand(&response, cmd, arguments);
+ }
+ QJsonDocument doc;
+ doc.setObject(response);
+ QByteArray ba = doc.toJson(QJsonDocument::Compact);
+ TRACE_PROTOCOL("Sending synchronous response:" << ba.constData() << endl);
+ emit messageToClient(s_key, ba);
+}
+
+void QQmlNativeDebugServiceImpl::emitAsynchronousMessageToClient(const QJsonObject &message)
+{
+ QJsonDocument doc;
+ doc.setObject(message);
+ QByteArray ba = doc.toJson(QJsonDocument::Compact);
+ TRACE_PROTOCOL("Sending asynchronous message:" << ba.constData() << endl);
+ emit messageToClient(s_key, ba);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.h b/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.h
new file mode 100644
index 0000000000..9d0780a203
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQML_NATIVE_DEBUG_SERVICE_H
+#define QQML_NATIVE_DEBUG_SERVICE_H
+
+#include <private/qqmldebugconnector_p.h>
+#include <private/qv4debugging_p.h>
+#include <private/qv8engine_p.h>
+#include <private/qv4engine_p.h>
+#include <private/qv4debugging_p.h>
+#include <private/qv4script_p.h>
+#include <private/qv4string_p.h>
+#include <private/qv4objectiterator_p.h>
+#include <private/qv4identifier_p.h>
+#include <private/qv4runtime_p.h>
+#include <private/qqmldebugserviceinterfaces_p.h>
+
+#include <QtCore/qjsonarray.h>
+
+#include <qqmlengine.h>
+
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QJsonValue>
+#include <QVector>
+#include <QPointer>
+
+QT_BEGIN_NAMESPACE
+
+class NativeDebugger;
+class BreakPointHandler;
+class QQmlDebuggerServiceFactory;
+
+class QQmlNativeDebugServiceImpl : public QQmlNativeDebugService
+{
+public:
+ QQmlNativeDebugServiceImpl(QObject *parent);
+
+ ~QQmlNativeDebugServiceImpl();
+
+ void engineAboutToBeAdded(QQmlEngine *engine);
+ void engineAboutToBeRemoved(QQmlEngine *engine);
+
+ void stateAboutToBeChanged(State state);
+
+ void messageReceived(const QByteArray &message);
+
+ void emitAsynchronousMessageToClient(const QJsonObject &message);
+
+private:
+ friend class QQmlDebuggerServiceFactory;
+ friend class NativeDebugger;
+
+ QList<QPointer<NativeDebugger> > m_debuggers;
+ BreakPointHandler *m_breakHandler;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQML_NATIVE_DEBUG_SERVICE_H
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
index b13c469893..377f0845d0 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
@@ -208,13 +208,13 @@ QV4DataCollector::Ref QV4DataCollector::addScriptRef(const QString &scriptName)
return ref;
}
-void QV4DataCollector::collectScope(QJsonObject *dict, QV4::Debugging::Debugger *debugger,
+void QV4DataCollector::collectScope(QJsonObject *dict, QV4::Debugging::V4Debugger *debugger,
int frameNr, int scopeNr)
{
QStringList names;
Refs refs;
- if (debugger->state() == QV4::Debugging::Debugger::Paused) {
+ if (debugger->state() == QV4::Debugging::V4Debugger::Paused) {
RefHolder holder(this, &refs);
ArgumentCollectJob argumentsJob(m_engine, this, &names, frameNr, scopeNr);
debugger->runInEngine(&argumentsJob);
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h
index 39d621e95e..0ea40f896c 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h
@@ -60,7 +60,7 @@ public:
Ref addFunctionRef(const QString &functionName);
Ref addScriptRef(const QString &scriptName);
- void collectScope(QJsonObject *dict, QV4::Debugging::Debugger *debugger, int frameNr,
+ void collectScope(QJsonObject *dict, QV4::Debugging::V4Debugger *debugger, int frameNr,
int scopeNr);
QV4::ExecutionEngine *engine() const { return m_engine; }
@@ -101,7 +101,7 @@ private:
QV4DataCollector::Refs *m_previousRefs;
};
-class ExpressionEvalJob: public QV4::Debugging::Debugger::JavaScriptJob
+class ExpressionEvalJob: public QV4::Debugging::V4Debugger::JavaScriptJob
{
QV4DataCollector *collector;
QString exception;
@@ -113,7 +113,7 @@ public:
const QString &exceptionMessage() const;
};
-class GatherSourcesJob: public QV4::Debugging::Debugger::Job
+class GatherSourcesJob: public QV4::Debugging::V4Debugger::Job
{
QV4::ExecutionEngine *engine;
QStringList sources;
@@ -124,7 +124,7 @@ public:
const QStringList &result() const;
};
-class ArgumentCollectJob: public QV4::Debugging::Debugger::Job
+class ArgumentCollectJob: public QV4::Debugging::V4Debugger::Job
{
QV4::ExecutionEngine *engine;
QV4DataCollector *collector;
@@ -138,7 +138,7 @@ public:
void run();
};
-class LocalCollectJob: public QV4::Debugging::Debugger::Job
+class LocalCollectJob: public QV4::Debugging::V4Debugger::Job
{
QV4::ExecutionEngine *engine;
QV4DataCollector *collector;
@@ -152,7 +152,7 @@ public:
void run();
};
-class ThisCollectJob: public QV4::Debugging::Debugger::Job
+class ThisCollectJob: public QV4::Debugging::V4Debugger::Job
{
QV4::ExecutionEngine *engine;
QV4DataCollector *collector;
@@ -166,7 +166,7 @@ public:
bool myRun();
};
-class ExceptionCollectJob: public QV4::Debugging::Debugger::Job
+class ExceptionCollectJob: public QV4::Debugging::V4Debugger::Job
{
QV4::ExecutionEngine *engine;
QV4DataCollector *collector;
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp
index 270a6958a9..dcb40dd548 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp
@@ -44,7 +44,7 @@ QV4DebuggerAgent::QV4DebuggerAgent(QV4DebugServiceImpl *debugService)
: m_breakOnThrow(false), m_debugService(debugService)
{}
-QV4::Debugging::Debugger *QV4DebuggerAgent::firstDebugger() const
+QV4::Debugging::V4Debugger *QV4DebuggerAgent::firstDebugger() const
{
// Currently only 1 single engine is supported, so:
if (m_debuggers.isEmpty())
@@ -56,13 +56,13 @@ QV4::Debugging::Debugger *QV4DebuggerAgent::firstDebugger() const
bool QV4DebuggerAgent::isRunning() const
{
// Currently only 1 single engine is supported, so:
- if (QV4::Debugging::Debugger *debugger = firstDebugger())
- return debugger->state() == QV4::Debugging::Debugger::Running;
+ if (QV4::Debugging::V4Debugger *debugger = firstDebugger())
+ return debugger->state() == QV4::Debugging::V4Debugger::Running;
else
return false;
}
-void QV4DebuggerAgent::debuggerPaused(QV4::Debugging::Debugger *debugger,
+void QV4DebuggerAgent::debuggerPaused(QV4::Debugging::V4Debugger *debugger,
QV4::Debugging::PauseReason reason)
{
Q_UNUSED(reason);
@@ -105,7 +105,7 @@ void QV4DebuggerAgent::debuggerPaused(QV4::Debugging::Debugger *debugger,
m_debugService->send(event);
}
-void QV4DebuggerAgent::addDebugger(QV4::Debugging::Debugger *debugger)
+void QV4DebuggerAgent::addDebugger(QV4::Debugging::V4Debugger *debugger)
{
Q_ASSERT(!m_debuggers.contains(debugger));
m_debuggers << debugger;
@@ -118,49 +118,55 @@ void QV4DebuggerAgent::addDebugger(QV4::Debugging::Debugger *debugger)
connect(debugger, SIGNAL(destroyed(QObject*)),
this, SLOT(handleDebuggerDeleted(QObject*)));
- connect(debugger, SIGNAL(debuggerPaused(QV4::Debugging::Debugger*,QV4::Debugging::PauseReason)),
- this, SLOT(debuggerPaused(QV4::Debugging::Debugger*,QV4::Debugging::PauseReason)),
+ connect(debugger,
+ SIGNAL(debuggerPaused(QV4::Debugging::V4Debugger*,QV4::Debugging::PauseReason)),
+ this, SLOT(debuggerPaused(QV4::Debugging::V4Debugger*,QV4::Debugging::PauseReason)),
Qt::QueuedConnection);
}
-void QV4DebuggerAgent::removeDebugger(QV4::Debugging::Debugger *debugger)
+void QV4DebuggerAgent::removeDebugger(QV4::Debugging::V4Debugger *debugger)
{
m_debuggers.removeAll(debugger);
disconnect(debugger, SIGNAL(destroyed(QObject*)),
this, SLOT(handleDebuggerDeleted(QObject*)));
disconnect(debugger,
- SIGNAL(debuggerPaused(QV4::Debugging::Debugger*,QV4::Debugging::PauseReason)),
+ SIGNAL(debuggerPaused(QV4::Debugging::V4Debugger*,QV4::Debugging::PauseReason)),
this,
- SLOT(debuggerPaused(QV4::Debugging::Debugger*,QV4::Debugging::PauseReason)));
+ SLOT(debuggerPaused(QV4::Debugging::V4Debugger*,QV4::Debugging::PauseReason)));
+}
+
+const QList<QV4::Debugging::V4Debugger *> &QV4DebuggerAgent::debuggers()
+{
+ return m_debuggers;
}
void QV4DebuggerAgent::handleDebuggerDeleted(QObject *debugger)
{
- m_debuggers.removeAll(static_cast<QV4::Debugging::Debugger *>(debugger));
+ m_debuggers.removeAll(static_cast<QV4::Debugging::V4Debugger *>(debugger));
}
-void QV4DebuggerAgent::pause(QV4::Debugging::Debugger *debugger) const
+void QV4DebuggerAgent::pause(QV4::Debugging::V4Debugger *debugger) const
{
debugger->pause();
}
void QV4DebuggerAgent::pauseAll() const
{
- foreach (QV4::Debugging::Debugger *debugger, m_debuggers)
+ foreach (QV4::Debugging::V4Debugger *debugger, m_debuggers)
pause(debugger);
}
void QV4DebuggerAgent::resumeAll() const
{
- foreach (QV4::Debugging::Debugger *debugger, m_debuggers)
- if (debugger->state() == QV4::Debugging::Debugger::Paused)
- debugger->resume(QV4::Debugging::Debugger::FullThrottle);
+ foreach (QV4::Debugging::V4Debugger *debugger, m_debuggers)
+ if (debugger->state() == QV4::Debugging::V4Debugger::Paused)
+ debugger->resume(QV4::Debugging::V4Debugger::FullThrottle);
}
int QV4DebuggerAgent::addBreakPoint(const QString &fileName, int lineNumber, bool enabled, const QString &condition)
{
if (enabled)
- foreach (QV4::Debugging::Debugger *debugger, m_debuggers)
+ foreach (QV4::Debugging::V4Debugger *debugger, m_debuggers)
debugger->addBreakPoint(fileName, lineNumber, condition);
int id = m_breakPoints.size();
@@ -177,7 +183,7 @@ void QV4DebuggerAgent::removeBreakPoint(int id)
m_breakPoints.remove(id);
if (breakPoint.enabled)
- foreach (QV4::Debugging::Debugger *debugger, m_debuggers)
+ foreach (QV4::Debugging::V4Debugger *debugger, m_debuggers)
debugger->removeBreakPoint(breakPoint.fileName, breakPoint.lineNr);
}
@@ -195,7 +201,7 @@ void QV4DebuggerAgent::enableBreakPoint(int id, bool onoff)
return;
breakPoint.enabled = onoff;
- foreach (QV4::Debugging::Debugger *debugger, m_debuggers) {
+ foreach (QV4::Debugging::V4Debugger *debugger, m_debuggers) {
if (onoff)
debugger->addBreakPoint(breakPoint.fileName, breakPoint.lineNr, breakPoint.condition);
else
@@ -218,7 +224,7 @@ void QV4DebuggerAgent::setBreakOnThrow(bool onoff)
{
if (onoff != m_breakOnThrow) {
m_breakOnThrow = onoff;
- foreach (QV4::Debugging::Debugger *debugger, m_debuggers)
+ foreach (QV4::Debugging::V4Debugger *debugger, m_debuggers)
debugger->setBreakOnThrow(onoff);
}
}
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h
index 64cf0e3d60..9f77a17b45 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h
@@ -46,13 +46,14 @@ class QV4DebuggerAgent : public QObject
public:
QV4DebuggerAgent(QV4DebugServiceImpl *m_debugService);
- QV4::Debugging::Debugger *firstDebugger() const;
+ QV4::Debugging::V4Debugger *firstDebugger() const;
bool isRunning() const;
- void addDebugger(QV4::Debugging::Debugger *debugger);
- void removeDebugger(QV4::Debugging::Debugger *debugger);
+ void addDebugger(QV4::Debugging::V4Debugger *debugger);
+ void removeDebugger(QV4::Debugging::V4Debugger *debugger);
+ const QList<QV4::Debugging::V4Debugger *> &debuggers();
- void pause(QV4::Debugging::Debugger *debugger) const;
+ void pause(QV4::Debugging::V4Debugger *debugger) const;
void pauseAll() const;
void resumeAll() const;
int addBreakPoint(const QString &fileName, int lineNumber, bool enabled = true, const QString &condition = QString());
@@ -65,11 +66,11 @@ public:
void setBreakOnThrow(bool onoff);
public slots:
- void debuggerPaused(QV4::Debugging::Debugger *debugger, QV4::Debugging::PauseReason reason);
+ void debuggerPaused(QV4::Debugging::V4Debugger *debugger, QV4::Debugging::PauseReason reason);
void handleDebuggerDeleted(QObject *debugger);
private:
- QList<QV4::Debugging::Debugger *> m_debuggers;
+ QList<QV4::Debugging::V4Debugger *> m_debuggers;
struct BreakPoint {
QString fileName;
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
index 14333e01f6..f742502e2a 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
@@ -34,6 +34,7 @@
#include "qv4debugservice.h"
#include "qqmlengine.h"
#include <private/qv4engine_p.h>
+#include <private/qv4isel_moth_p.h>
#include <private/qv4function_p.h>
#include <private/qqmldebugconnector_p.h>
#include <private/qpacket_p.h>
@@ -269,7 +270,7 @@ public:
int toFrame = arguments.value(QStringLiteral("toFrame")).toInt(fromFrame + 10);
// no idea what the bottom property is for, so we'll ignore it.
- QV4::Debugging::Debugger *debugger = debugService->debuggerAgent.firstDebugger();
+ QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
QJsonArray frameArray;
QVector<QV4::StackFrame> frames = debugger->stackTrace(toFrame);
@@ -306,7 +307,7 @@ public:
const int frameNr = arguments.value(QStringLiteral("number")).toInt(
debugService->selectedFrame());
- QV4::Debugging::Debugger *debugger = debugService->debuggerAgent.firstDebugger();
+ QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
QVector<QV4::StackFrame> frames = debugger->stackTrace(frameNr + 1);
if (frameNr < 0 || frameNr >= frames.size()) {
createErrorResponse(QStringLiteral("frame command has invalid frame number"));
@@ -339,7 +340,7 @@ public:
debugService->selectedFrame());
const int scopeNr = arguments.value(QStringLiteral("number")).toInt(0);
- QV4::Debugging::Debugger *debugger = debugService->debuggerAgent.firstDebugger();
+ QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
QVector<QV4::StackFrame> frames = debugger->stackTrace(frameNr + 1);
if (frameNr < 0 || frameNr >= frames.size()) {
createErrorResponse(QStringLiteral("scope command has invalid frame number"));
@@ -397,10 +398,10 @@ public:
// decypher the payload:
QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
- QV4::Debugging::Debugger *debugger = debugService->debuggerAgent.firstDebugger();
+ QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
if (arguments.empty()) {
- debugger->resume(QV4::Debugging::Debugger::FullThrottle);
+ debugger->resume(QV4::Debugging::V4Debugger::FullThrottle);
} else {
QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
QString stepAction = arguments.value(QStringLiteral("stepaction")).toString();
@@ -409,11 +410,11 @@ public:
qWarning() << "Step count other than 1 is not supported.";
if (stepAction == QStringLiteral("in")) {
- debugger->resume(QV4::Debugging::Debugger::StepIn);
+ debugger->resume(QV4::Debugging::V4Debugger::StepIn);
} else if (stepAction == QStringLiteral("out")) {
- debugger->resume(QV4::Debugging::Debugger::StepOut);
+ debugger->resume(QV4::Debugging::V4Debugger::StepOut);
} else if (stepAction == QStringLiteral("next")) {
- debugger->resume(QV4::Debugging::Debugger::StepOver);
+ debugger->resume(QV4::Debugging::V4Debugger::StepOver);
} else {
createErrorResponse(QStringLiteral("continue command has invalid stepaction"));
return;
@@ -505,7 +506,7 @@ public:
}
// do it:
- QV4::Debugging::Debugger *debugger = debugService->debuggerAgent.firstDebugger();
+ QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
GatherSourcesJob job(debugger->engine());
debugger->runInEngine(&job);
@@ -560,8 +561,8 @@ public:
virtual void handleRequest()
{
- QV4::Debugging::Debugger *debugger = debugService->debuggerAgent.firstDebugger();
- if (debugger->state() == QV4::Debugging::Debugger::Paused) {
+ QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
+ if (debugger->state() == QV4::Debugging::V4Debugger::Paused) {
QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
QString expression = arguments.value(QStringLiteral("expression")).toString();
const int frame = arguments.value(QStringLiteral("frame")).toInt(0);
@@ -632,8 +633,11 @@ void QV4DebugServiceImpl::engineAboutToBeAdded(QQmlEngine *engine)
QV4::ExecutionEngine *ee = QV8Engine::getV4(engine->handle());
if (QQmlDebugConnector *server = QQmlDebugConnector::instance()) {
if (ee) {
- ee->enableDebugger();
- debuggerAgent.addDebugger(ee->debugger);
+ ee->iselFactory.reset(new QV4::Moth::ISelFactory);
+ QV4::Debugging::V4Debugger *debugger = new QV4::Debugging::V4Debugger(ee);
+ if (state() == Enabled)
+ ee->setDebugger(debugger);
+ debuggerAgent.addDebugger(debugger);
debuggerAgent.moveToThread(server->thread());
}
}
@@ -646,12 +650,29 @@ void QV4DebugServiceImpl::engineAboutToBeRemoved(QQmlEngine *engine)
QMutexLocker lock(&m_configMutex);
if (engine){
const QV4::ExecutionEngine *ee = QV8Engine::getV4(engine->handle());
- if (ee)
- debuggerAgent.removeDebugger(ee->debugger);
+ if (ee) {
+ QV4::Debugging::V4Debugger *debugger
+ = qobject_cast<QV4::Debugging::V4Debugger *>(ee->debugger);
+ if (debugger)
+ debuggerAgent.removeDebugger(debugger);
+ }
}
QQmlConfigurableDebugService<QV4DebugService>::engineAboutToBeRemoved(engine);
}
+void QV4DebugServiceImpl::stateAboutToBeChanged(State state)
+{
+ QMutexLocker lock(&m_configMutex);
+ if (state == Enabled) {
+ foreach (QV4::Debugging::V4Debugger *debugger, debuggerAgent.debuggers()) {
+ QV4::ExecutionEngine *ee = debugger->engine();
+ if (!ee->debugger)
+ ee->setDebugger(debugger);
+ }
+ }
+ QQmlConfigurableDebugService<QV4DebugService>::stateAboutToBeChanged(state);
+}
+
void QV4DebugServiceImpl::signalEmitted(const QString &signal)
{
//This function is only called by QQmlBoundSignal
@@ -766,7 +787,7 @@ void QV4DebugServiceImpl::clearHandles(QV4::ExecutionEngine *engine)
}
QJsonObject QV4DebugServiceImpl::buildFrame(const QV4::StackFrame &stackFrame, int frameNr,
- QV4::Debugging::Debugger *debugger)
+ QV4::Debugging::V4Debugger *debugger)
{
QV4DataCollector::Ref ref;
@@ -784,7 +805,7 @@ QJsonObject QV4DebugServiceImpl::buildFrame(const QV4::StackFrame &stackFrame, i
frame[QLatin1String("column")] = stackFrame.column;
QJsonArray scopes;
- if (debugger->state() == QV4::Debugging::Debugger::Paused) {
+ if (debugger->state() == QV4::Debugging::V4Debugger::Paused) {
RefHolder holder(theCollector.data(), &collectedRefs);
bool foundThis = false;
ThisCollectJob job(debugger->engine(), theCollector.data(), frameNr, &foundThis);
@@ -834,7 +855,7 @@ int QV4DebugServiceImpl::encodeScopeType(QV4::Heap::ExecutionContext::ContextTyp
}
QJsonObject QV4DebugServiceImpl::buildScope(int frameNr, int scopeNr,
- QV4::Debugging::Debugger *debugger)
+ QV4::Debugging::V4Debugger *debugger)
{
QJsonObject scope;
@@ -842,7 +863,7 @@ QJsonObject QV4DebugServiceImpl::buildScope(int frameNr, int scopeNr,
RefHolder holder(theCollector.data(), &collectedRefs);
theCollector->collectScope(&object, debugger, frameNr, scopeNr);
- if (debugger->state() == QV4::Debugging::Debugger::Paused) {
+ if (debugger->state() == QV4::Debugging::V4Debugger::Paused) {
QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes =
QV4DataCollector::getScopeTypes(debugger->engine(), frameNr);
scope[QLatin1String("type")] = encodeScopeType(scopeTypes[scopeNr]);
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h
index dbf41ac363..ea4a695fed 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h
@@ -73,16 +73,18 @@ public:
void engineAboutToBeAdded(QQmlEngine *engine);
void engineAboutToBeRemoved(QQmlEngine *engine);
+ void stateAboutToBeChanged(State state);
+
void signalEmitted(const QString &signal);
void send(QJsonObject v8Payload);
- QJsonObject buildScope(int frameNr, int scopeNr, QV4::Debugging::Debugger *debugger);
+ QJsonObject buildScope(int frameNr, int scopeNr, QV4::Debugging::V4Debugger *debugger);
QJsonArray buildRefs();
QJsonValue lookup(QV4DataCollector::Ref refId);
QJsonValue toRef(QV4DataCollector::Ref ref);
QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr,
- QV4::Debugging::Debugger *debugger);
+ QV4::Debugging::V4Debugger *debugger);
int selectedFrame() const;
void selectFrame(int frameNr);
diff --git a/src/plugins/qmltooling/qmldbg_native/qmldbg_native.pro b/src/plugins/qmltooling/qmldbg_native/qmldbg_native.pro
new file mode 100644
index 0000000000..7dc16b8c44
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_native/qmldbg_native.pro
@@ -0,0 +1,12 @@
+TARGET = qmldbg_native
+QT += qml-private core-private
+
+PLUGIN_TYPE = qmltooling
+PLUGIN_CLASS_NAME = QQmlNativeDebugConnectorFactory
+load(qt_plugin)
+
+SOURCES += \
+ $$PWD/qqmlnativedebugconnector.cpp
+
+OTHER_FILES += \
+ $$PWD/qqmlnativedebugconnector.json
diff --git a/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.cpp b/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.cpp
new file mode 100644
index 0000000000..018b10d3e7
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.cpp
@@ -0,0 +1,384 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qqmldebugconnector_p.h>
+#include <private/qhooks_p.h>
+#include <private/qpacket_p.h>
+
+#include <qqmlengine.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qjsondocument.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qjsonvalue.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qvector.h>
+
+//#define TRACE_PROTOCOL(s) qDebug() << s
+#define TRACE_PROTOCOL(s)
+
+QT_USE_NAMESPACE
+
+static bool expectSyncronousResponse = false;
+Q_GLOBAL_STATIC(QByteArray, responseBuffer)
+
+extern "C" {
+
+Q_DECL_EXPORT const char *qt_qmlDebugMessageBuffer;
+Q_DECL_EXPORT int qt_qmlDebugMessageLength;
+Q_DECL_EXPORT bool qt_qmlDebugConnectionBlocker;
+
+// In blocking mode, this will busy wait until the debugger sets block to false.
+Q_DECL_EXPORT void qt_qmlDebugConnectorOpen();
+
+// First thing, set the debug stream version. Please use this function as we might move the version
+// member to some other place.
+Q_DECL_EXPORT void qt_qmlDebugSetStreamVersion(int version)
+{
+ QPacket::setDataStreamVersion(version);
+}
+
+
+// Break in this one to process output from an asynchronous message/
+Q_DECL_EXPORT void qt_qmlDebugMessageAvailable()
+{
+}
+
+
+// Break in this one to get notified about construction and destruction of
+// interesting objects, such as QmlEngines.
+Q_DECL_EXPORT void qt_qmlDebugObjectAvailable()
+{
+}
+
+Q_DECL_EXPORT void qt_qmlDebugClearBuffer()
+{
+ responseBuffer->clear();
+}
+
+// Send a message to a service.
+Q_DECL_EXPORT bool qt_qmlDebugSendDataToService(const char *serviceName, const char *hexData)
+{
+ QByteArray msg = QByteArray::fromHex(hexData);
+
+ QQmlDebugConnector *instance = QQmlDebugConnector::instance();
+ if (!instance)
+ return false;
+
+ QQmlDebugService *recipient = instance->service(serviceName);
+ if (!recipient)
+ return false;
+
+ TRACE_PROTOCOL("Recipient: " << recipient << " got message: " << msg);
+ expectSyncronousResponse = true;
+ recipient->messageReceived(msg);
+ expectSyncronousResponse = false;
+
+ return true;
+}
+
+// Enable a service.
+Q_DECL_EXPORT bool qt_qmlDebugEnableService(const char *data)
+{
+ QQmlDebugConnector *instance = QQmlDebugConnector::instance();
+ if (!instance)
+ return false;
+
+ QString name = QString::fromLatin1(data);
+ QQmlDebugService *service = instance->service(name);
+ if (!service || service->state() == QQmlDebugService::Enabled)
+ return false;
+
+ service->stateAboutToBeChanged(QQmlDebugService::Enabled);
+ service->setState(QQmlDebugService::Enabled);
+ service->stateChanged(QQmlDebugService::Enabled);
+ return true;
+}
+
+Q_DECL_EXPORT bool qt_qmlDebugDisableService(const char *data)
+{
+ QQmlDebugConnector *instance = QQmlDebugConnector::instance();
+ if (!instance)
+ return false;
+
+ QString name = QString::fromLatin1(data);
+ QQmlDebugService *service = instance->service(name);
+ if (!service || service->state() == QQmlDebugService::Unavailable)
+ return false;
+
+ service->stateAboutToBeChanged(QQmlDebugService::Unavailable);
+ service->setState(QQmlDebugService::Unavailable);
+ service->stateChanged(QQmlDebugService::Unavailable);
+ return true;
+}
+
+quintptr qt_qmlDebugTestHooks[] = {
+ quintptr(1), // Internal Version
+ quintptr(6), // Number of entries following
+ quintptr(&qt_qmlDebugMessageBuffer),
+ quintptr(&qt_qmlDebugMessageLength),
+ quintptr(&qt_qmlDebugSendDataToService),
+ quintptr(&qt_qmlDebugEnableService),
+ quintptr(&qt_qmlDebugDisableService),
+ quintptr(&qt_qmlDebugObjectAvailable)
+};
+
+// In blocking mode, this will busy wait until the debugger sets block to false.
+Q_DECL_EXPORT void qt_qmlDebugConnectorOpen()
+{
+ TRACE_PROTOCOL("Opening native debug connector");
+
+ // FIXME: Use a dedicated hook. Startup is a safe workaround, though,
+ // as we are already beyond its only use.
+ qtHookData[QHooks::Startup] = quintptr(&qt_qmlDebugTestHooks);
+
+ while (qt_qmlDebugConnectionBlocker)
+ ;
+
+ TRACE_PROTOCOL("Opened native debug connector");
+}
+
+} // extern "C"
+
+QT_BEGIN_NAMESPACE
+
+class QQmlNativeDebugConnector : public QQmlDebugConnector
+{
+ Q_OBJECT
+
+public:
+ QQmlNativeDebugConnector();
+ ~QQmlNativeDebugConnector();
+
+ bool blockingMode() const;
+ QQmlDebugService *service(const QString &name) const;
+ void addEngine(QQmlEngine *engine);
+ void removeEngine(QQmlEngine *engine);
+ bool addService(const QString &name, QQmlDebugService *service);
+ bool removeService(const QString &name);
+ bool open(const QVariantHash &configuration);
+
+private slots:
+ void sendMessage(const QString &name, const QByteArray &message);
+ void sendMessages(const QString &name, const QList<QByteArray> &messages);
+
+private:
+ void announceObjectAvailability(const QString &objectType, QObject *object, bool available);
+
+ QVector<QQmlDebugService *> m_services;
+ bool m_blockingMode;
+};
+
+QQmlNativeDebugConnector::QQmlNativeDebugConnector()
+ : m_blockingMode(false)
+{
+ const QString args = commandLineArguments();
+ const QStringList lstjsDebugArguments = args.split(QLatin1Char(','));
+ QStringList services;
+ QStringList::const_iterator argsItEnd = lstjsDebugArguments.cend();
+ QStringList::const_iterator argsIt = lstjsDebugArguments.cbegin();
+ for (; argsIt != argsItEnd; ++argsIt) {
+ const QString strArgument = *argsIt;
+ if (strArgument == QLatin1String("block")) {
+ m_blockingMode = true;
+ } else if (strArgument == QLatin1String("native")) {
+ // Ignore. This is used to signal that this connector
+ // should be loaded and that has already happened.
+ } else if (strArgument.startsWith(QLatin1String("services:"))) {
+ services.append(strArgument.mid(9));
+ } else if (!services.isEmpty()) {
+ services.append(strArgument);
+ } else {
+ qWarning("QML Debugger: Invalid argument \"%s\" detected. Ignoring the same.",
+ qUtf8Printable(strArgument));
+ }
+ }
+ setServices(services);
+}
+
+QQmlNativeDebugConnector::~QQmlNativeDebugConnector()
+{
+ foreach (QQmlDebugService *service, m_services) {
+ service->stateAboutToBeChanged(QQmlDebugService::NotConnected);
+ service->setState(QQmlDebugService::NotConnected);
+ service->stateChanged(QQmlDebugService::NotConnected);
+ }
+}
+
+bool QQmlNativeDebugConnector::blockingMode() const
+{
+ return m_blockingMode;
+}
+
+QQmlDebugService *QQmlNativeDebugConnector::service(const QString &name) const
+{
+ for (QVector<QQmlDebugService *>::ConstIterator i = m_services.begin(); i != m_services.end();
+ ++i) {
+ if ((*i)->name() == name)
+ return *i;
+ }
+ return 0;
+}
+
+void QQmlNativeDebugConnector::addEngine(QQmlEngine *engine)
+{
+ TRACE_PROTOCOL("Add engine to connector:" << engine);
+ foreach (QQmlDebugService *service, m_services)
+ service->engineAboutToBeAdded(engine);
+
+ announceObjectAvailability(QLatin1String("qmlengine"), engine, true);
+
+ foreach (QQmlDebugService *service, m_services)
+ service->engineAdded(engine);
+}
+
+void QQmlNativeDebugConnector::removeEngine(QQmlEngine *engine)
+{
+ TRACE_PROTOCOL("Remove engine from connector:" << engine);
+ foreach (QQmlDebugService *service, m_services)
+ service->engineAboutToBeRemoved(engine);
+
+ announceObjectAvailability(QLatin1String("qmlengine"), engine, false);
+
+ foreach (QQmlDebugService *service, m_services)
+ service->engineRemoved(engine);
+}
+
+void QQmlNativeDebugConnector::announceObjectAvailability(const QString &objectType,
+ QObject *object, bool available)
+{
+ QJsonObject ob;
+ ob.insert(QLatin1String("objecttype"), objectType);
+ ob.insert(QLatin1String("object"), QString::number(quintptr(object)));
+ ob.insert(QLatin1String("available"), available);
+ QJsonDocument doc;
+ doc.setObject(ob);
+
+ QByteArray ba = doc.toJson(QJsonDocument::Compact);
+ qt_qmlDebugMessageBuffer = ba.constData();
+ qt_qmlDebugMessageLength = ba.size();
+ TRACE_PROTOCOL("Reporting engine availabilty");
+ qt_qmlDebugObjectAvailable(); // Trigger native breakpoint.
+}
+
+bool QQmlNativeDebugConnector::addService(const QString &name, QQmlDebugService *service)
+{
+ TRACE_PROTOCOL("Add service to connector: " << qPrintable(name) << service);
+ for (QVector<QQmlDebugService *>::ConstIterator i = m_services.begin(); i != m_services.end();
+ ++i) {
+ if ((*i)->name() == name)
+ return false;
+ }
+
+ connect(service, &QQmlDebugService::messageToClient,
+ this, &QQmlNativeDebugConnector::sendMessage);
+ connect(service, &QQmlDebugService::messagesToClient,
+ this, &QQmlNativeDebugConnector::sendMessages);
+
+ service->setState(QQmlDebugService::Unavailable);
+
+ m_services << service;
+ return true;
+}
+
+bool QQmlNativeDebugConnector::removeService(const QString &name)
+{
+ for (QVector<QQmlDebugService *>::Iterator i = m_services.begin(); i != m_services.end(); ++i) {
+ if ((*i)->name() == name) {
+ QQmlDebugService *service = *i;
+ m_services.erase(i);
+ service->setState(QQmlDebugService::NotConnected);
+
+ disconnect(service, &QQmlDebugService::messagesToClient,
+ this, &QQmlNativeDebugConnector::sendMessages);
+ disconnect(service, &QQmlDebugService::messageToClient,
+ this, &QQmlNativeDebugConnector::sendMessage);
+
+ return true;
+ }
+ }
+ return false;
+}
+
+bool QQmlNativeDebugConnector::open(const QVariantHash &configuration)
+{
+ m_blockingMode = configuration.value(QStringLiteral("block"), m_blockingMode).toBool();
+ qt_qmlDebugConnectionBlocker = m_blockingMode;
+ qt_qmlDebugConnectorOpen();
+ return true;
+}
+
+void QQmlNativeDebugConnector::sendMessage(const QString &name, const QByteArray &message)
+{
+ (*responseBuffer) += name.toUtf8() + ' ' + QByteArray::number(message.size()) + ' ' + message;
+ qt_qmlDebugMessageBuffer = responseBuffer->constData();
+ qt_qmlDebugMessageLength = responseBuffer->size();
+ // Responses are allowed to accumulate, the buffer will be cleared by
+ // separate calls to qt_qmlDebugClearBuffer() once the synchronous
+ // function return ('if' branch below) or in the native breakpoint handler
+ // ('else' branch below).
+ if (expectSyncronousResponse) {
+ TRACE_PROTOCOL("Expected synchronous response in " << message);
+ // Do not trigger the native breakpoint on qt_qmlDebugMessageFromService.
+ } else {
+ TRACE_PROTOCOL("Found asynchronous message in " << message);
+ // Trigger native breakpoint.
+ qt_qmlDebugMessageAvailable();
+ }
+}
+
+void QQmlNativeDebugConnector::sendMessages(const QString &name, const QList<QByteArray> &messages)
+{
+ for (int i = 0; i != messages.size(); ++i)
+ sendMessage(name, messages.at(i));
+}
+
+class QQmlNativeDebugConnectorFactory : public QQmlDebugConnectorFactory
+{
+ Q_OBJECT
+
+ Q_PLUGIN_METADATA(IID QQmlDebugConnectorFactory_iid FILE "qqmlnativedebugconnector.json")
+
+public:
+ QQmlNativeDebugConnectorFactory() {}
+
+ QQmlDebugConnector *create(const QString &key)
+ {
+ return key == QLatin1String("QQmlNativeDebugConnector") ? new QQmlNativeDebugConnector : 0;
+ }
+};
+
+QT_END_NAMESPACE
+
+#include "qqmlnativedebugconnector.moc"
diff --git a/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.json b/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.json
new file mode 100644
index 0000000000..925e6a665c
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "QQmlNativeDebugConnector" ]
+}
diff --git a/src/plugins/qmltooling/qmltooling.pro b/src/plugins/qmltooling/qmltooling.pro
index 75da89f3e8..5b39747674 100644
--- a/src/plugins/qmltooling/qmltooling.pro
+++ b/src/plugins/qmltooling/qmltooling.pro
@@ -2,6 +2,7 @@ TEMPLATE = subdirs
# Connectors
SUBDIRS += \
+ qmldbg_native \
qmldbg_server \
qmldbg_local \
qmldbg_tcp
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index bc4068085a..2b0383beec 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -2028,33 +2028,16 @@ private:
}
};
-class EliminateDeadCode: public ExprVisitor {
- DefUses &_defUses;
- StatementWorklist &_worklist;
+class SideEffectsChecker: public ExprVisitor
+{
bool _sideEffect;
- QVector<Temp *> _collectedTemps;
public:
- EliminateDeadCode(DefUses &defUses, StatementWorklist &worklist)
- : _defUses(defUses)
- , _worklist(worklist)
- , _sideEffect(false)
- {
- _collectedTemps.reserve(8);
- }
-
- void run(Expr *&expr, Stmt *stmt) {
- if (!checkForSideEffects(expr)) {
- expr = 0;
- foreach (Temp *t, _collectedTemps) {
- _defUses.removeUse(stmt, *t);
- _worklist += _defUses.defStmt(*t);
- }
- }
- }
+ SideEffectsChecker()
+ : _sideEffect(false)
+ {}
-private:
- bool checkForSideEffects(Expr *expr)
+ bool hasSideEffects(Expr *expr)
{
bool sideEffect = false;
qSwap(_sideEffect, sideEffect);
@@ -2063,19 +2046,20 @@ private:
return sideEffect;
}
+protected:
void markAsSideEffect()
{
_sideEffect = true;
- _collectedTemps.clear();
}
+ bool seenSideEffects() const { return _sideEffect; }
+
protected:
- virtual void visitConst(Const *) {}
- virtual void visitString(IR::String *) {}
- virtual void visitRegExp(IR::RegExp *) {}
+ void visitConst(Const *) Q_DECL_OVERRIDE {}
+ void visitString(IR::String *) Q_DECL_OVERRIDE {}
+ void visitRegExp(IR::RegExp *) Q_DECL_OVERRIDE {}
- virtual void visitName(Name *e)
- {
+ void visitName(Name *e) Q_DECL_OVERRIDE {
if (e->freeOfSideEffects)
return;
// TODO: maybe we can distinguish between built-ins of which we know that they do not have
@@ -2084,19 +2068,14 @@ protected:
markAsSideEffect();
}
- virtual void visitTemp(Temp *e)
- {
- _collectedTemps.append(e);
- }
-
- virtual void visitArgLocal(ArgLocal *) {}
+ void visitTemp(Temp *) Q_DECL_OVERRIDE {}
+ void visitArgLocal(ArgLocal *) Q_DECL_OVERRIDE {}
- virtual void visitClosure(Closure *)
- {
+ void visitClosure(Closure *) Q_DECL_OVERRIDE {
markAsSideEffect();
}
- virtual void visitConvert(Convert *e) {
+ void visitConvert(Convert *e) Q_DECL_OVERRIDE {
e->expr->accept(this);
switch (e->expr->type) {
@@ -2110,7 +2089,7 @@ protected:
}
}
- virtual void visitUnop(Unop *e) {
+ void visitUnop(Unop *e) Q_DECL_OVERRIDE {
e->expr->accept(this);
switch (e->op) {
@@ -2128,39 +2107,39 @@ protected:
}
}
- virtual void visitBinop(Binop *e) {
+ void visitBinop(Binop *e) Q_DECL_OVERRIDE {
// TODO: prune parts that don't have a side-effect. For example, in:
// function f(x) { +x+1; return 0; }
// we can prune the binop and leave the unop/conversion.
- _sideEffect = checkForSideEffects(e->left);
- _sideEffect |= checkForSideEffects(e->right);
+ _sideEffect = hasSideEffects(e->left);
+ _sideEffect |= hasSideEffects(e->right);
if (e->left->type == VarType || e->left->type == StringType || e->left->type == QObjectType
|| e->right->type == VarType || e->right->type == StringType || e->right->type == QObjectType)
markAsSideEffect();
}
- virtual void visitSubscript(Subscript *e) {
+ void visitSubscript(Subscript *e) Q_DECL_OVERRIDE {
e->base->accept(this);
e->index->accept(this);
markAsSideEffect();
}
- virtual void visitMember(Member *e) {
+ void visitMember(Member *e) Q_DECL_OVERRIDE {
e->base->accept(this);
if (e->freeOfSideEffects)
return;
markAsSideEffect();
}
- virtual void visitCall(Call *e) {
+ void visitCall(Call *e) Q_DECL_OVERRIDE {
e->base->accept(this);
for (ExprList *args = e->args; args; args = args->next)
args->expr->accept(this);
markAsSideEffect(); // TODO: there are built-in functions that have no side effect.
}
- virtual void visitNew(New *e) {
+ void visitNew(New *e) Q_DECL_OVERRIDE {
e->base->accept(this);
for (ExprList *args = e->args; args; args = args->next)
args->expr->accept(this);
@@ -2168,6 +2147,38 @@ protected:
}
};
+class EliminateDeadCode: public SideEffectsChecker
+{
+ DefUses &_defUses;
+ StatementWorklist &_worklist;
+ QVector<Temp *> _collectedTemps;
+
+public:
+ EliminateDeadCode(DefUses &defUses, StatementWorklist &worklist)
+ : _defUses(defUses)
+ , _worklist(worklist)
+ {
+ _collectedTemps.reserve(8);
+ }
+
+ void run(Expr *&expr, Stmt *stmt) {
+ _collectedTemps.clear();
+ if (!hasSideEffects(expr)) {
+ expr = 0;
+ foreach (Temp *t, _collectedTemps) {
+ _defUses.removeUse(stmt, *t);
+ _worklist += _defUses.defStmt(*t);
+ }
+ }
+ }
+
+protected:
+ void visitTemp(Temp *e) Q_DECL_OVERRIDE
+ {
+ _collectedTemps.append(e);
+ }
+};
+
struct DiscoveredType {
int type;
MemberExpressionResolver *memberResolver;
@@ -4928,6 +4939,39 @@ static void verifyNoPointerSharing(IR::Function *function)
V(function);
}
+class RemoveLineNumbers: public SideEffectsChecker, public StmtVisitor
+{
+public:
+ static void run(IR::Function *function)
+ {
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
+ foreach (Stmt *s, bb->statements()) {
+ if (!hasSideEffects(s)) {
+ s->location = QQmlJS::AST::SourceLocation();
+ }
+ }
+ }
+ }
+
+private:
+ static bool hasSideEffects(Stmt *stmt)
+ {
+ RemoveLineNumbers checker;
+ stmt->accept(&checker);
+ return checker.seenSideEffects();
+ }
+
+ void visitExp(Exp *s) Q_DECL_OVERRIDE { s->expr->accept(this); }
+ void visitMove(Move *s) Q_DECL_OVERRIDE { s->source->accept(this); s->target->accept(this); }
+ void visitJump(Jump *) Q_DECL_OVERRIDE {}
+ void visitCJump(CJump *s) Q_DECL_OVERRIDE { s->cond->accept(this); }
+ void visitRet(Ret *s) Q_DECL_OVERRIDE { s->expr->accept(this); }
+ void visitPhi(Phi *) Q_DECL_OVERRIDE {}
+};
+
} // anonymous namespace
void LifeTimeInterval::setFrom(int from) {
@@ -5260,6 +5304,11 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine, bool doTypeInference, bool pee
checkCriticalEdges(function->basicBlocks());
#endif
+ if (!function->module->debugMode) {
+ RemoveLineNumbers::run(function);
+ showMeTheCode(function, "After line number removal");
+ }
+
// qout << "Finished SSA." << endl;
inSSA = true;
} else {
diff --git a/src/qml/debugger/qqmldebugconnector.cpp b/src/qml/debugger/qqmldebugconnector.cpp
index 460cb8f203..64a8a49bb9 100644
--- a/src/qml/debugger/qqmldebugconnector.cpp
+++ b/src/qml/debugger/qqmldebugconnector.cpp
@@ -45,10 +45,12 @@
QT_BEGIN_NAMESPACE
-// We could add more plugins here, and distinguish by arguments to instance()
+// Connectors. We could add more plugins here, and distinguish by arguments to instance()
Q_QML_DEBUG_PLUGIN_LOADER(QQmlDebugConnector)
Q_QML_IMPORT_DEBUG_PLUGIN(QQmlDebugServerFactory)
+Q_QML_IMPORT_DEBUG_PLUGIN(QQmlNativeDebugConnectorFactory)
+// Services
Q_QML_DEBUG_PLUGIN_LOADER(QQmlDebugService)
Q_QML_IMPORT_DEBUG_PLUGIN(QQmlInspectorServiceFactory)
Q_QML_IMPORT_DEBUG_PLUGIN(QQmlProfilerServiceFactory)
@@ -116,13 +118,20 @@ QQmlDebugConnector *QQmlDebugConnector::instance()
}
if (!params->instance) {
+ const QString serverConnector = QStringLiteral("QQmlDebugServer");
+ const QString nativeConnector = QStringLiteral("QQmlNativeDebugConnector");
+ const bool isNative = params->arguments.startsWith(QStringLiteral("native"));
if (!params->pluginKey.isEmpty()) {
- if (params->pluginKey != QLatin1String("QQmlDebugServer"))
+ if (params->pluginKey == serverConnector || params->pluginKey == nativeConnector)
+ params->instance = loadQQmlDebugConnector(params->pluginKey);
+ else
return 0; // We cannot load anything else, yet
} else if (params->arguments.isEmpty()) {
return 0; // no explicit class name given and no command line arguments
+ } else {
+ params->instance = loadQQmlDebugConnector(isNative ? nativeConnector : serverConnector);
}
- params->instance = loadQQmlDebugConnector(QLatin1String("QQmlDebugServer"));
+
if (params->instance) {
foreach (const QJsonObject &object, metaDataForQQmlDebugService()) {
foreach (const QJsonValue &key, object.value(QLatin1String("MetaData")).toObject()
diff --git a/src/qml/debugger/qqmldebugpluginmanager_p.h b/src/qml/debugger/qqmldebugpluginmanager_p.h
index cef463b8b3..6fffa67d7b 100644
--- a/src/qml/debugger/qqmldebugpluginmanager_p.h
+++ b/src/qml/debugger/qqmldebugpluginmanager_p.h
@@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE
}\
QList<QJsonObject> metaDataFor##interfaceName()\
{\
- return QList<QJsonObject();\
+ return QList<QJsonObject>();\
}
#define Q_QML_IMPORT_DEBUG_PLUGIN(className)
@@ -70,7 +70,9 @@ QT_BEGIN_NAMESPACE
#ifdef QT_STATIC
#define Q_QML_IMPORT_DEBUG_PLUGIN(className)\
- Q_IMPORT_PLUGIN(className)
+ QT_END_NAMESPACE\
+ Q_IMPORT_PLUGIN(className)\
+ QT_BEGIN_NAMESPACE
#else
#define Q_QML_IMPORT_DEBUG_PLUGIN(className)
#endif // QT_STATIC
diff --git a/src/qml/debugger/qqmldebugserviceinterfaces.cpp b/src/qml/debugger/qqmldebugserviceinterfaces.cpp
index 992b007e86..e0968b2656 100644
--- a/src/qml/debugger/qqmldebugserviceinterfaces.cpp
+++ b/src/qml/debugger/qqmldebugserviceinterfaces.cpp
@@ -41,5 +41,6 @@ const QString QQmlInspectorService::s_key = QStringLiteral("QmlInspector");
const QString QQmlProfilerService::s_key = QStringLiteral("CanvasFrameRate");
const QString QDebugMessageService::s_key = QStringLiteral("DebugMessages");
const QString QQmlEngineControlService::s_key = QStringLiteral("EngineControl");
+const QString QQmlNativeDebugService::s_key = QStringLiteral("NativeQmlDebugger");
QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmldebugserviceinterfaces_p.h b/src/qml/debugger/qqmldebugserviceinterfaces_p.h
index 54f9114159..a2193b5c59 100644
--- a/src/qml/debugger/qqmldebugserviceinterfaces_p.h
+++ b/src/qml/debugger/qqmldebugserviceinterfaces_p.h
@@ -154,6 +154,19 @@ protected:
};
+class Q_QML_PRIVATE_EXPORT QQmlNativeDebugService : protected QQmlDebugService
+{
+ Q_OBJECT
+
+protected:
+ friend class QQmlDebugConnector;
+
+ QQmlNativeDebugService(float version, QObject *parent = 0)
+ : QQmlDebugService(s_key, version, parent) {}
+
+ static const QString s_key;
+};
+
QT_END_NAMESPACE
#endif // QQMLDEBUGSERVICEINTERFACES_P_H
diff --git a/src/qml/doc/qtqml.qdocconf b/src/qml/doc/qtqml.qdocconf
index 74b61fd6e1..500754ead4 100644
--- a/src/qml/doc/qtqml.qdocconf
+++ b/src/qml/doc/qtqml.qdocconf
@@ -4,7 +4,7 @@ project = QtQml
description = Qt QML Reference Documentation
version = $QT_VERSION
-examplesinstallpath = qml
+examplesinstallpath = qtdeclarative/qml
qhp.projects = QtQml
diff --git a/src/qml/doc/snippets/qml/qtBinding.2.qml b/src/qml/doc/snippets/qml/qtBinding.2.qml
index 6a9a2de750..6159b31748 100644
--- a/src/qml/doc/snippets/qml/qtBinding.2.qml
+++ b/src/qml/doc/snippets/qml/qtBinding.2.qml
@@ -52,7 +52,7 @@ Item {
root.dynamicText = "Modified root text"
var obj2 = c.createObject(root, { 'text': Qt.binding(function() { return this.dynamicText + ' extra text' }) })
- obj2.dynamicText = "Modified text element text"
+ obj2.dynamicText = "Modified dynamic text"
}
}
//![0]
diff --git a/src/qml/doc/src/javascript/hostenvironment.qdoc b/src/qml/doc/src/javascript/hostenvironment.qdoc
index 3b1763bd50..e613c4fcfb 100644
--- a/src/qml/doc/src/javascript/hostenvironment.qdoc
+++ b/src/qml/doc/src/javascript/hostenvironment.qdoc
@@ -71,7 +71,7 @@ Note that QML makes the following modifications to native objects:
\list
\li An \l {String::arg}{arg()} function is added to the \l String prototype.
-\li Locale-aware coversion functions are added to the \l Date and \l Number prototypes.
+\li Locale-aware conversion functions are added to the \l Date and \l Number prototypes.
\endlist
diff --git a/src/qml/doc/src/javascript/resources.qdoc b/src/qml/doc/src/javascript/resources.qdoc
index 51354e9bf0..b831e2ba70 100644
--- a/src/qml/doc/src/javascript/resources.qdoc
+++ b/src/qml/doc/src/javascript/resources.qdoc
@@ -57,7 +57,7 @@ parameters if they are required.
An example of a code-behind implementation resource follows:
-\qml
+\code
// MyButton.qml
import QtQuick 2.0
import "my_button_impl.js" as Logic // a new instance of this JavaScript resource is loaded for each instance of Button.qml
@@ -74,11 +74,11 @@ Rectangle {
onClicked: Logic.onClicked(rect)
}
}
-\endqml
+\endcode
-\qml
+\code
// my_button_impl.js
-var clickCount = 0; // this state is separate for each instance of MyButton
+property var clickCount = 0; // this state is separate for each instance of MyButton
function onClicked(btn) {
clickCount += 1;
if ((clickCount % 5) == 0) {
@@ -87,7 +87,7 @@ function onClicked(btn) {
obj.color = Qt.rgba(0,1,0,1);
}
}
-\endqml
+\endcode
In general, simple logic should be defined in-line in the QML file, but more
complex logic should be separated into code-behind implementation resources
@@ -138,7 +138,7 @@ within a QML document which never calls the factorial function.
For example:
-\qml
+\code
// Calculator.qml
import QtQuick 2.0
import "factorial.js" as FactorialCalculator // this JavaScript resource is only ever loaded once by the engine, even if multiple instances of Calculator.qml are created
@@ -149,7 +149,7 @@ Text {
property int input: 17
text: "The factorial of " + input + " is: " + FactorialCalculator.factorial(input)
}
-\endqml
+\endcode
As they are shared, .pragma library files cannot access QML component instance
objects or properties directly, although QML values can be passed as function
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 403beacf39..007bf92639 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -114,23 +114,32 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable)
Scope scope(this);
// find the right context to create the binding on
- ScopedObject activation(scope, d()->engine->globalObject);
+ ScopedObject activation(scope);
ScopedContext ctx(scope, this);
while (ctx) {
switch (ctx->d()->type) {
case Heap::ExecutionContext::Type_CallContext:
case Heap::ExecutionContext::Type_SimpleCallContext: {
Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
- if (!c->activation)
- c->activation = scope.engine->newObject();
- activation = c->activation;
+ if (!activation) {
+ if (!c->activation)
+ c->activation = scope.engine->newObject();
+ activation = c->activation;
+ }
break;
}
case Heap::ExecutionContext::Type_QmlContext: {
+ // this is ugly, as it overrides the inner callcontext, but has to stay as long
+ // as bindings still get their own callcontext
Heap::QmlContext *qml = static_cast<Heap::QmlContext *>(ctx->d());
activation = qml->qml;
break;
}
+ case Heap::ExecutionContext::Type_GlobalContext: {
+ if (!activation)
+ activation = scope.engine->globalObject;
+ break;
+ }
default:
break;
}
diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp
index 79fd58f700..7706a40da6 100644
--- a/src/qml/jsruntime/qv4debugging.cpp
+++ b/src/qml/jsruntime/qv4debugging.cpp
@@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE
using namespace QV4;
using namespace QV4::Debugging;
-Debugger::JavaScriptJob::JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr,
+V4Debugger::JavaScriptJob::JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr,
const QString &script)
: engine(engine)
, frameNr(frameNr)
@@ -62,7 +62,7 @@ Debugger::JavaScriptJob::JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr
, resultIsException(false)
{}
-void Debugger::JavaScriptJob::run()
+void V4Debugger::JavaScriptJob::run()
{
Scope scope(engine);
@@ -92,18 +92,18 @@ void Debugger::JavaScriptJob::run()
handleResult(result);
}
-bool Debugger::JavaScriptJob::hasExeption() const
+bool V4Debugger::JavaScriptJob::hasExeption() const
{
return resultIsException;
}
-class EvalJob: public Debugger::JavaScriptJob
+class EvalJob: public V4Debugger::JavaScriptJob
{
bool result;
public:
EvalJob(QV4::ExecutionEngine *engine, const QString &script)
- : Debugger::JavaScriptJob(engine, /*frameNr*/-1, script)
+ : V4Debugger::JavaScriptJob(engine, /*frameNr*/-1, script)
, result(false)
{}
@@ -118,7 +118,7 @@ public:
}
};
-Debugger::Debugger(QV4::ExecutionEngine *engine)
+V4Debugger::V4Debugger(QV4::ExecutionEngine *engine)
: m_engine(engine)
, m_state(Running)
, m_stepping(NotStepping)
@@ -129,11 +129,11 @@ Debugger::Debugger(QV4::ExecutionEngine *engine)
, m_gatherSources(0)
, m_runningJob(0)
{
- qMetaTypeId<Debugger*>();
+ qMetaTypeId<V4Debugger*>();
qMetaTypeId<PauseReason>();
}
-void Debugger::pause()
+void V4Debugger::pause()
{
QMutexLocker locker(&m_lock);
if (m_state == Paused)
@@ -141,7 +141,7 @@ void Debugger::pause()
m_pauseRequested = true;
}
-void Debugger::resume(Speed speed)
+void V4Debugger::resume(Speed speed)
{
QMutexLocker locker(&m_lock);
if (m_state != Paused)
@@ -155,28 +155,28 @@ void Debugger::resume(Speed speed)
m_runningCondition.wakeAll();
}
-void Debugger::addBreakPoint(const QString &fileName, int lineNumber, const QString &condition)
+void V4Debugger::addBreakPoint(const QString &fileName, int lineNumber, const QString &condition)
{
QMutexLocker locker(&m_lock);
m_breakPoints.insert(DebuggerBreakPoint(fileName.mid(fileName.lastIndexOf('/') + 1), lineNumber), condition);
m_haveBreakPoints = true;
}
-void Debugger::removeBreakPoint(const QString &fileName, int lineNumber)
+void V4Debugger::removeBreakPoint(const QString &fileName, int lineNumber)
{
QMutexLocker locker(&m_lock);
m_breakPoints.remove(DebuggerBreakPoint(fileName.mid(fileName.lastIndexOf('/') + 1), lineNumber));
m_haveBreakPoints = !m_breakPoints.isEmpty();
}
-void Debugger::setBreakOnThrow(bool onoff)
+void V4Debugger::setBreakOnThrow(bool onoff)
{
QMutexLocker locker(&m_lock);
m_breakOnThrow = onoff;
}
-Debugger::ExecutionState Debugger::currentExecutionState() const
+V4Debugger::ExecutionState V4Debugger::currentExecutionState() const
{
ExecutionState state;
state.fileName = getFunction()->sourceFile();
@@ -185,12 +185,12 @@ Debugger::ExecutionState Debugger::currentExecutionState() const
return state;
}
-QVector<StackFrame> Debugger::stackTrace(int frameLimit) const
+QVector<StackFrame> V4Debugger::stackTrace(int frameLimit) const
{
return m_engine->stackTrace(frameLimit);
}
-void Debugger::maybeBreakAtInstruction()
+void V4Debugger::maybeBreakAtInstruction()
{
if (m_runningJob) // do not re-enter when we're doing a job for the debugger.
return;
@@ -228,7 +228,7 @@ void Debugger::maybeBreakAtInstruction()
}
}
-void Debugger::enteringFunction()
+void V4Debugger::enteringFunction()
{
if (m_runningJob)
return;
@@ -239,7 +239,7 @@ void Debugger::enteringFunction()
}
}
-void Debugger::leavingFunction(const ReturnedValue &retVal)
+void V4Debugger::leavingFunction(const ReturnedValue &retVal)
{
if (m_runningJob)
return;
@@ -254,7 +254,7 @@ void Debugger::leavingFunction(const ReturnedValue &retVal)
}
}
-void Debugger::aboutToThrow()
+void V4Debugger::aboutToThrow()
{
if (!m_breakOnThrow)
return;
@@ -266,7 +266,7 @@ void Debugger::aboutToThrow()
pauseAndWait(Throwing);
}
-Function *Debugger::getFunction() const
+Function *V4Debugger::getFunction() const
{
Scope scope(m_engine);
ExecutionContext *context = m_engine->currentContext;
@@ -277,7 +277,7 @@ Function *Debugger::getFunction() const
return context->d()->engine->globalCode;
}
-void Debugger::pauseAndWait(PauseReason reason)
+void V4Debugger::pauseAndWait(PauseReason reason)
{
if (m_runningJob)
return;
@@ -298,7 +298,7 @@ void Debugger::pauseAndWait(PauseReason reason)
m_state = Running;
}
-bool Debugger::reallyHitTheBreakPoint(const QString &filename, int linenr)
+bool V4Debugger::reallyHitTheBreakPoint(const QString &filename, int linenr)
{
BreakPoints::iterator it = m_breakPoints.find(DebuggerBreakPoint(filename.mid(filename.lastIndexOf('/') + 1), linenr));
if (it == m_breakPoints.end())
@@ -316,13 +316,13 @@ bool Debugger::reallyHitTheBreakPoint(const QString &filename, int linenr)
return evilJob.resultAsBoolean();
}
-void Debugger::runInEngine(Debugger::Job *job)
+void V4Debugger::runInEngine(V4Debugger::Job *job)
{
QMutexLocker locker(&m_lock);
runInEngine_havingLock(job);
}
-void Debugger::runInEngine_havingLock(Debugger::Job *job)
+void V4Debugger::runInEngine_havingLock(V4Debugger::Job *job)
{
Q_ASSERT(job);
Q_ASSERT(m_runningJob == 0);
@@ -333,7 +333,7 @@ void Debugger::runInEngine_havingLock(Debugger::Job *job)
m_runningJob = 0;
}
-Debugger::Job::~Job()
+V4Debugger::Job::~Job()
{
}
diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h
index 14bff238cc..683036882e 100644
--- a/src/qml/jsruntime/qv4debugging_p.h
+++ b/src/qml/jsruntime/qv4debugging_p.h
@@ -93,6 +93,19 @@ typedef QHash<DebuggerBreakPoint, QString> BreakPoints;
class Q_QML_EXPORT Debugger : public QObject
{
Q_OBJECT
+
+public:
+ virtual ~Debugger() {}
+ virtual bool pauseAtNextOpportunity() const = 0;
+ virtual void maybeBreakAtInstruction() = 0;
+ virtual void enteringFunction() = 0;
+ virtual void leavingFunction(const ReturnedValue &retVal) = 0;
+ virtual void aboutToThrow() = 0;
+};
+
+class Q_QML_EXPORT V4Debugger : public Debugger
+{
+ Q_OBJECT
public:
class Q_QML_EXPORT Job
{
@@ -131,7 +144,7 @@ public:
NotStepping = FullThrottle
};
- Debugger(ExecutionEngine *engine);
+ V4Debugger(ExecutionEngine *engine);
ExecutionEngine *engine() const
{ return m_engine; }
@@ -173,13 +186,13 @@ public: // execution hooks
void aboutToThrow();
signals:
- void debuggerPaused(QV4::Debugging::Debugger *self, QV4::Debugging::PauseReason reason);
+ void debuggerPaused(QV4::Debugging::V4Debugger *self, QV4::Debugging::PauseReason reason);
private:
// requires lock to be held
void pauseAndWait(PauseReason reason);
bool reallyHitTheBreakPoint(const QString &filename, int linenr);
- void runInEngine_havingLock(Debugger::Job *job);
+ void runInEngine_havingLock(V4Debugger::Job *job);
private:
QV4::ExecutionEngine *m_engine;
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 6fe14da850..82d94f569e 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -518,11 +518,10 @@ ExecutionEngine::~ExecutionEngine()
delete [] argumentsAccessors;
}
-void ExecutionEngine::enableDebugger()
+void ExecutionEngine::setDebugger(Debugging::Debugger *debugger_)
{
Q_ASSERT(!debugger);
- debugger = new Debugging::Debugger(this);
- iselFactory.reset(new Moth::ISelFactory);
+ debugger = debugger_;
}
void ExecutionEngine::enableProfiler()
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index e94b417908..4640f3f4cc 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -366,7 +366,7 @@ public:
ExecutionEngine(EvalISelFactory *iselFactory = 0);
~ExecutionEngine();
- void enableDebugger();
+ void setDebugger(Debugging::Debugger *debugger);
void enableProfiler();
ExecutionContext *pushGlobalContext();
diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp
index f1face007c..3d3ac84576 100644
--- a/src/qml/jsruntime/qv4mathobject.cpp
+++ b/src/qml/jsruntime/qv4mathobject.cpp
@@ -277,10 +277,15 @@ Q_GLOBAL_STATIC(QThreadStorage<bool *>, seedCreatedStorage);
ReturnedValue MathObject::method_random(CallContext *context)
{
if (!seedCreatedStorage()->hasLocalData()) {
- qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()) ^ reinterpret_cast<quintptr>(context));
+ int msecs = QTime(0,0,0).msecsTo(QTime::currentTime());
+ Q_ASSERT(msecs >= 0);
+ qsrand(uint(uint(msecs) ^ reinterpret_cast<quintptr>(context)));
seedCreatedStorage()->setLocalData(new bool(true));
}
- return Encode(qrand() / (double) RAND_MAX);
+ // rand()/qrand() return a value where the upperbound is RAND_MAX inclusive. So, instead of
+ // dividing by RAND_MAX (which would return 0..RAND_MAX inclusive), we divide by RAND_MAX + 1.
+ qint64 upperLimit = qint64(RAND_MAX) + 1;
+ return Encode(qrand() / double(upperLimit));
}
ReturnedValue MathObject::method_round(CallContext *context)
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index ee3539c176..ba29d52bc6 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -1107,7 +1107,7 @@ void Object::copyArrayData(Object *other)
dd->len = other->d()->arrayData->len;
dd->offset = other->d()->arrayData->offset;
}
- memcpy(d()->arrayData->arrayData, other->d()->arrayData->arrayData, d()->arrayData->alloc*sizeof(Value));
+ memcpy(d()->arrayData->arrayData, other->d()->arrayData->arrayData, other->d()->arrayData->alloc*sizeof(Value));
}
setArrayLengthUnchecked(other->getLength());
}
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 26271e3f03..1a27a487bd 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -242,7 +242,12 @@ void QQmlType::SingletonInstanceInfo::destroy(QQmlEngine *e)
// cleans up the engine-specific singleton instances if they exist.
scriptApis.remove(e);
QObject *o = qobjectApis.take(e);
- delete o;
+ if (o) {
+ QQmlData *ddata = QQmlData::get(o, false);
+ if (ddata && ddata->indestructible)
+ return;
+ delete o;
+ }
}
void QQmlType::SingletonInstanceInfo::setQObjectApi(QQmlEngine *e, QObject *o)
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index 413eca8a68..af0742d2c6 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -76,8 +76,7 @@ struct QQmlVMEMetaData
short aliasCount;
short signalCount;
short methodCount;
- short dummyForAlignment; // Add padding to ensure that the following
- // AliasData/PropertyData/MethodData is int aligned.
+ // Make sure this structure is always aligned to int
struct AliasData {
int contextIdx;
diff --git a/src/qml/types/qqmlinstantiator.cpp b/src/qml/types/qqmlinstantiator.cpp
index 735463a058..448a591e22 100644
--- a/src/qml/types/qqmlinstantiator.cpp
+++ b/src/qml/types/qqmlinstantiator.cpp
@@ -426,7 +426,7 @@ void QQmlInstantiator::setModel(const QVariant &v)
}
/*!
- \qmlproperty QtQml::QtObject QtQml::Instantiator::object
+ \qmlproperty QtObject QtQml::Instantiator::object
This is a reference to the first created object, intended as a convenience
for the case where only one object has been created.
@@ -440,7 +440,7 @@ QObject *QQmlInstantiator::object() const
}
/*!
- \qmlmethod QtQml::QtObject QtQml::Instantiator::objectAt
+ \qmlmethod QtObject QtQml::Instantiator::objectAt(int index)
Returns a reference to the object with the given \a index.
*/
diff --git a/src/qml/types/qqmlitemmodels.qdoc b/src/qml/types/qqmlitemmodels.qdoc
index 4e64aaa338..6733330209 100644
--- a/src/qml/types/qqmlitemmodels.qdoc
+++ b/src/qml/types/qqmlitemmodels.qdoc
@@ -26,7 +26,8 @@
****************************************************************************/
/*!
- \chapter QModelIndex & Co. in QML
+ \page qmodelindex-and-related-classes-in-qml.html
+ \title QModelIndex and related Classes in QML
Since Qt 5.5, QModelIndex and QPersistentModelIndex are exposed in QML as
value-based types. Also exposed in a similar fashion are QModelIndexList,
@@ -34,15 +35,14 @@
be passed back and forth between QML and C++ as \c var properties or plain
JavaScript variables.
- We detail here which API all these classes get exposed in QML. Please refer
- to the C++ documentation for more information.
+ Below you will find an overview of the API exposed to QML for these classes.
+ For more information, refer to their C++ documentation.
- \note Since all these types are exposed as gadgets, there are no property
+ \note Since all these types are exposed as \l{Q_GADGET}{gadgets}, there are no property
change notification signals emitted. Therefore binding to their properties
may not give the expected results. This is especially true for QPersistentModelIndex.
- It is perfectly possible to bind to properties holding any of those types.
- \section1 \l QModelIndex and \l QPersistentModelIndex
+ \section1 QModelIndex and QPersistentModelIndex Types
\list
\li \b row : int
@@ -53,25 +53,25 @@
\li \b internalId : quint64
\endlist
- All these properties are read-only, as their C++ counterpart.
+ All these properties are read-only, as are their C++ counterparts.
\note The usual caveats apply to QModelIndex in QML. If the underlying model changes
or gets deleted, it may become dangerous to access its properties. Therefore, you
- should not store any QModelIndex. You can, however, store QPersistentModelIndexes
- in a safe way.
+ should not store any QModelIndex objects. You can, however, store QPersistentModelIndexe
+ objects in a safe way.
- \section1 QModelIndexList
+ \section1 QModelIndexList Type
\l QModelIndexList is exposed in QML as a JavaScript array. Conversions are
automatically made from and to C++. In fact, any JavaScript array can be
converted back to QModelIndexList, with non-QModelIndex objects replaced by
- invalid QModelIndexes.
+ invalid \l{QModelIndex}es.
\note QModelIndex to QPersistentModelIndex conversion happens when accessing
the array elements because any QModelIndexList property retains reference
semantics when exposed this way.
- \section1 \l QItemSelectionRange
+ \section1 \l QItemSelectionRange Type
\list
\li \b top : int
@@ -88,22 +88,22 @@
\li \b model : QAbstractItemModel
\endlist
- All these properties are read-only, as their C++ counterpart. In addition,
+ All these properties are read-only, as are their C++ counterparts. In addition,
we also expose the following functions:
\list
- \li bool \b{contains}(QModelIndex index)
- \li bool \b{contains}(int row, int column, QModelIndex parentIndex)
- \li bool \b{intersects}(QItemSelectionRange other)
- \li QItemSelectionRange \b{intersected}(QItemSelectionRange other)
+ \li bool \b{contains}(QModelIndex \e index)
+ \li bool \b{contains}(int \e row, int \e column, QModelIndex \e parentIndex)
+ \li bool \b{intersects}(QItemSelectionRange \e other)
+ \li QItemSelectionRange \b{intersected}(QItemSelectionRange \e other)
\endlist
- \section1 QItemSelection
+ \section1 QItemSelection Type
Similarly to QModelIndexList, \l QItemSelection is exposed in QML as a JavaScript
- array of QItemSelectionRanges. Conversions are automatically made from and to C++.
+ array of QItemSelectionRange objects. Conversions are automatically made from and to C++.
In fact, any JavaScript array can be converted back to QItemSelection, with
- non-QItemSelectionRange objects replaced by empty QItemSelectionRanges.
+ non-QItemSelectionRange objects replaced by empty \l {QItemSelectionRange}s.
\sa ItemSelectionModel
diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp
index 4ccfdb9142..44a2caecec 100644
--- a/src/quick/accessible/qaccessiblequickitem.cpp
+++ b/src/quick/accessible/qaccessiblequickitem.cpp
@@ -204,11 +204,12 @@ QAccessible::Role QAccessibleQuickItem::role() const
if (qobject_cast<QQuickText*>(const_cast<QQuickItem *>(item())))
return QAccessible::StaticText;
- QVariant v = QQuickAccessibleAttached::property(item(), "role");
- bool ok;
- QAccessible::Role role = (QAccessible::Role)v.toInt(&ok);
- if (!ok) // Not sure if this check is needed.
+ QAccessible::Role role = QAccessible::NoRole;
+ if (item())
+ role = QQuickItemPrivate::get(item())->accessibleRole();
+ if (role == QAccessible::NoRole)
role = QAccessible::Client;
+
return role;
}
diff --git a/src/quick/doc/qtquick.qdocconf b/src/quick/doc/qtquick.qdocconf
index 7f43dc2c31..044c1696ff 100644
--- a/src/quick/doc/qtquick.qdocconf
+++ b/src/quick/doc/qtquick.qdocconf
@@ -4,7 +4,7 @@ project = QtQuick
description = Qt Quick Reference Documentation
version = $QT_VERSION
-examplesinstallpath = quick
+examplesinstallpath = qtdeclarative/quick
qhp.projects = QtQuick
diff --git a/src/quick/doc/src/concepts/effects/sprites.qdoc b/src/quick/doc/src/concepts/effects/sprites.qdoc
index edad89b1e5..62d9ea0811 100644
--- a/src/quick/doc/src/concepts/effects/sprites.qdoc
+++ b/src/quick/doc/src/concepts/effects/sprites.qdoc
@@ -26,13 +26,10 @@
****************************************************************************/
/*!
-\ingroup qtquick-images-sprites
\page qtquick-effects-sprites.html
\title Sprite Animations
\brief Sprite-based animations with flexible transitioning
-\generatelist{related}
-
\section1 Sprite Engine
The \l {Qt Quick} sprite engine is a stochastic state machine combined with the ability
@@ -167,9 +164,9 @@ Additionally, \l ImageParticle can use \l Sprite types to define sprites for eac
sprite engine per type. This works similarly to SpriteSequence, but it also has the parametrized variability provided
by the \l ImageParticle type.
-\section1 AnimatedSprite
+\section1 AnimatedSprite Type
-For use-cases which do not need to transition between animations, consider the \l AnimatedSprite type.
+For use-cases which do not need to transition between animations, consider the AnimatedSprite type.
This type displays sprite animations with the same input format, but only one at a time. It also provides more fine-grained
manual control, as there is no sprite engine managing the timing and transitions behind the scenes.
diff --git a/src/quick/doc/src/concepts/effects/transformations.qdoc b/src/quick/doc/src/concepts/effects/transformations.qdoc
index a5c7b9c208..cfe9d420fa 100644
--- a/src/quick/doc/src/concepts/effects/transformations.qdoc
+++ b/src/quick/doc/src/concepts/effects/transformations.qdoc
@@ -31,8 +31,6 @@
\title Qt Quick Transformation Types
\brief Types for applying transformations to visual types
-\generatelist{related}
-
Transformations are applied to child hierarchies and also will also transform
mouse and touch input so coordinates in event handlers behave as expected.
diff --git a/src/quick/doc/src/concepts/input/textinput.qdoc b/src/quick/doc/src/concepts/input/textinput.qdoc
index 3965c246da..41508caad6 100644
--- a/src/quick/doc/src/concepts/input/textinput.qdoc
+++ b/src/quick/doc/src/concepts/input/textinput.qdoc
@@ -26,7 +26,6 @@
****************************************************************************/
/*!
-\ingroup qtquick-text
\page qtquick-input-textinput.html
\title Qt Quick Text Input Handling and Validators
\brief Text input and validation
@@ -38,8 +37,6 @@ type will display formatted text onto the screen, the \l TextEdit type
will place a multiline line edit onto the screen, and the \l TextInput will
place a single editable line field onto the screen.
-\generatelist{related}
-
To learn more about their specific features and properties, visit their
respective documentation.
@@ -63,11 +60,11 @@ Note that QML parses JavaScript regular expressions, while Qt's
*/
/*!
+\page qtquick-text-validator.html
\ingroup qtquick-text-validator
\title Qt Quick Text Validators
\brief Types that validate text input
-The \l{qtquick-concepts-input-text.html}
-{Qt Quick Text Input Handling and Validators} page has information about
+The \l {Qt Quick Text Input Handling and Validators} page has information about
validating user text input.
*/
diff --git a/src/quick/doc/src/concepts/positioning/layouts.qdoc b/src/quick/doc/src/concepts/positioning/layouts.qdoc
index de47af6db8..47ed2563f8 100644
--- a/src/quick/doc/src/concepts/positioning/layouts.qdoc
+++ b/src/quick/doc/src/concepts/positioning/layouts.qdoc
@@ -26,7 +26,6 @@
****************************************************************************/
/*!
-\ingroup qtquick-positioners
\page qtquick-positioning-layouts.html
\title Item Positioners
@@ -47,7 +46,7 @@ and are well suited for resizable user interfaces.
A set of standard positioners are provided in the basic set of Qt Quick
graphical types:
-\generatelist{related}
+\annotatedlist qtquick-positioners
\section2 Column
diff --git a/src/quick/doc/src/concepts/statesanimations/animations.qdoc b/src/quick/doc/src/concepts/statesanimations/animations.qdoc
index ee174d2dad..1a2cff43f4 100644
--- a/src/quick/doc/src/concepts/statesanimations/animations.qdoc
+++ b/src/quick/doc/src/concepts/statesanimations/animations.qdoc
@@ -295,27 +295,3 @@ Rectangle {
\endqml
*/
-
-/*!
-\ingroup qtquick-animation-properties
-\title Qt Quick Property Animation
-\brief Animate property changes
-
-\generatelist{related}
-*/
-
-/*!
-\ingroup qtquick-animation-control
-\title Qt Quick Animation Controls
-\brief Control animation sequences
-
-\generatelist{related}
-*/
-
-/*!
-\ingroup qtquick-animation-modifiers
-\title Qt Quick Animation Modifiers
-\brief Modify animation sequences
-
-\generatelist{related}
-*/
diff --git a/src/quick/doc/src/concepts/statesanimations/states.qdoc b/src/quick/doc/src/concepts/statesanimations/states.qdoc
index d107369e44..b48a051379 100644
--- a/src/quick/doc/src/concepts/statesanimations/states.qdoc
+++ b/src/quick/doc/src/concepts/statesanimations/states.qdoc
@@ -26,13 +26,12 @@
****************************************************************************/
/*!
-\ingroup qtquick-states
\page qtquick-statesanimations-states.html
\title Qt Quick States
\brief Creating and setting states
\section1 Related Types
-\generatelist{related}
+\annotatedlist qtquick-states
Many user interface designs are \e{state driven}; interfaces have configurations
that differ depending on the current state. For example, a traffic signal will
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index b378398730..bf53b0f3ea 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -2714,7 +2714,15 @@ void QQuickItem::setParentItem(QQuickItem *parentItem)
/*!
Moves the specified \a sibling item to the index before this item
- within the visual stacking order.
+ within the list of children. The order of children affects both the
+ visual stacking order and tab focus navigation order.
+
+ Assuming the z values of both items are the same, this will cause \a
+ sibling to be rendered above this item.
+
+ If both items have activeFocusOnTab set to \c true, this will also cause
+ the tab focus order to change, with \a sibling receiving focus after this
+ item.
The given \a sibling must be a sibling of this item; that is, they must
have the same immediate \l parent.
@@ -2750,7 +2758,15 @@ void QQuickItem::stackBefore(const QQuickItem *sibling)
/*!
Moves the specified \a sibling item to the index after this item
- within the visual stacking order.
+ within the list of children. The order of children affects both the
+ visual stacking order and tab focus navigation order.
+
+ Assuming the z values of both items are the same, this will cause \a
+ sibling to be rendered below this item.
+
+ If both items have activeFocusOnTab set to \c true, this will also cause
+ the tab focus order to change, with \a sibling receiving focus before this
+ item.
The given \a sibling must be a sibling of this item; that is, they must
have the same immediate \l parent.
@@ -8030,6 +8046,19 @@ QQuickItemPrivate::ExtraData::ExtraData()
{
}
+
+#ifndef QT_NO_ACCESSIBILITY
+QAccessible::Role QQuickItemPrivate::accessibleRole() const
+{
+ Q_Q(const QQuickItem);
+ QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q, false));
+ if (accessibleAttached)
+ return accessibleAttached->role();
+
+ return QAccessible::NoRole;
+}
+#endif
+
QT_END_NAMESPACE
#include <moc_qquickitem.cpp>
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index 9172f7eff1..634aa2b658 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -534,6 +534,10 @@ public:
virtual void implicitWidthChanged();
virtual void implicitHeightChanged();
+#ifndef QT_NO_ACCESSIBILITY
+ virtual QAccessible::Role accessibleRole() const;
+#endif
+
void setImplicitAntialiasing(bool antialiasing);
void resolveLayoutMirror();
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index c8256ed62a..6542bde4f1 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -3306,7 +3306,8 @@ QImage QQuickWindow::grabWindow()
d->syncSceneGraph();
d->renderSceneGraph(size());
- QImage image = qt_gl_read_framebuffer(size() * effectiveDevicePixelRatio(), false, false);
+ bool alpha = format().alphaBufferSize() > 0 && color().alpha() < 255;
+ QImage image = qt_gl_read_framebuffer(size() * effectiveDevicePixelRatio(), alpha, alpha);
d->cleanupNodesOnShutdown();
d->context->invalidate();
context.doneCurrent();
diff --git a/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp b/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp
index 8293c106b5..f7c9fe7fae 100644
--- a/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp
+++ b/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp
@@ -63,24 +63,6 @@ void QSGNodeUpdater::updateStates(QSGNode *n)
visitNode(n);
}
-/*!
- \fn void QSGNodeUpdater::setToplevelOpacity(qreal opacity)
-
- Sets the toplevel opacity that will be multiplied with the
-
- The default opacity is 1. Any other value will cause artifacts, and is
- primarily useful for debug purposes.
-
- The changing the value during an update pass will have undefined results
- */
-
-/*!
- \fn qreal QSGNodeUpdater::toplevelOpacity() const
-
- Returns the toplevel opacity for the node updater. The default
- value is 1.
- */
-
/*!
Returns true if \a node is has something that blocks it in the chain from
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index 3059b750f2..87dd521807 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -398,7 +398,8 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame);
if (data.grabOnly) {
- grabContent = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), false, false);
+ bool alpha = window->format().alphaBufferSize() > 0 && window->color().alpha() != 255;
+ grabContent = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), alpha, alpha);
data.grabOnly = false;
}
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 4b78fefa99..8d6bea9e67 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -421,7 +421,8 @@ bool QSGRenderThread::event(QEvent *e)
QQuickWindowPrivate::get(ce->window)->renderSceneGraph(ce->window->size());
qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- grabbing result";
- *ce->image = qt_gl_read_framebuffer(windowSize * ce->window->effectiveDevicePixelRatio(), false, false);
+ bool alpha = ce->window->format().alphaBufferSize() > 0 && ce->window->color().alpha() != 255;
+ *ce->image = qt_gl_read_framebuffer(windowSize * ce->window->effectiveDevicePixelRatio(), alpha, alpha);
}
qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- waking gui to handle result";
waitCondition.wakeOne();
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
index 7fd9651618..04a46bf929 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp
+++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
@@ -312,7 +312,8 @@ QImage QSGWindowsRenderLoop::grab(QQuickWindow *window)
d->syncSceneGraph();
d->renderSceneGraph(window->size());
- QImage image = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), false, false);
+ bool alpha = window->format().alphaBufferSize() > 0 && window->color().alpha() != 255;
+ QImage image = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), alpha, alpha);
return image;
}
diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp
index ec3abf7090..1d0dbf64b3 100644
--- a/src/quick/util/qquickanimation.cpp
+++ b/src/quick/util/qquickanimation.cpp
@@ -2179,7 +2179,7 @@ void QQuickPropertyAnimation::setTo(const QVariant &t)
\li \inlineimage qeasingcurve-incubic.png
\row
\li \c Easing.OutCubic
- \li Easing curve for a cubic (t^3) function: decelerating from zero velocity.
+ \li Easing curve for a cubic (t^3) function: decelerating to zero velocity.
\li \inlineimage qeasingcurve-outcubic.png
\row
\li \c Easing.InOutCubic
@@ -2195,7 +2195,7 @@ void QQuickPropertyAnimation::setTo(const QVariant &t)
\li \inlineimage qeasingcurve-inquart.png
\row
\li \c Easing.OutQuart
- \li Easing curve for a quartic (t^4) function: decelerating from zero velocity.
+ \li Easing curve for a quartic (t^4) function: decelerating to zero velocity.
\li \inlineimage qeasingcurve-outquart.png
\row
\li \c Easing.InOutQuart
@@ -2211,7 +2211,7 @@ void QQuickPropertyAnimation::setTo(const QVariant &t)
\li \inlineimage qeasingcurve-inquint.png
\row
\li \c Easing.OutQuint
- \li Easing curve for a quintic (t^5) function: decelerating from zero velocity.
+ \li Easing curve for a quintic (t^5) function: decelerating to zero velocity.
\li \inlineimage qeasingcurve-outquint.png
\row
\li \c Easing.InOutQuint
@@ -2227,7 +2227,7 @@ void QQuickPropertyAnimation::setTo(const QVariant &t)
\li \inlineimage qeasingcurve-insine.png
\row
\li \c Easing.OutSine
- \li Easing curve for a sinusoidal (sin(t)) function: decelerating from zero velocity.
+ \li Easing curve for a sinusoidal (sin(t)) function: decelerating to zero velocity.
\li \inlineimage qeasingcurve-outsine.png
\row
\li \c Easing.InOutSine
@@ -2243,7 +2243,7 @@ void QQuickPropertyAnimation::setTo(const QVariant &t)
\li \inlineimage qeasingcurve-inexpo.png
\row
\li \c Easing.OutExpo
- \li Easing curve for an exponential (2^t) function: decelerating from zero velocity.
+ \li Easing curve for an exponential (2^t) function: decelerating to zero velocity.
\li \inlineimage qeasingcurve-outexpo.png
\row
\li \c Easing.InOutExpo
@@ -2259,7 +2259,7 @@ void QQuickPropertyAnimation::setTo(const QVariant &t)
\li \inlineimage qeasingcurve-incirc.png
\row
\li \c Easing.OutCirc
- \li Easing curve for a circular (sqrt(1-t^2)) function: decelerating from zero velocity.
+ \li Easing curve for a circular (sqrt(1-t^2)) function: decelerating to zero velocity.
\li \inlineimage qeasingcurve-outcirc.png
\row
\li \c Easing.InOutCirc
@@ -2276,7 +2276,7 @@ void QQuickPropertyAnimation::setTo(const QVariant &t)
\li \inlineimage qeasingcurve-inelastic.png
\row
\li \c Easing.OutElastic
- \li Easing curve for an elastic (exponentially decaying sine wave) function: decelerating from zero velocity.
+ \li Easing curve for an elastic (exponentially decaying sine wave) function: decelerating to zero velocity.
\br The peak amplitude can be set with the \e amplitude parameter, and the period of decay by the \e period parameter.
\li \inlineimage qeasingcurve-outelastic.png
\row
@@ -2309,7 +2309,7 @@ void QQuickPropertyAnimation::setTo(const QVariant &t)
\li \inlineimage qeasingcurve-inbounce.png
\row
\li \c Easing.OutBounce
- \li Easing curve for a bounce (exponentially decaying parabolic bounce) function: decelerating from zero velocity.
+ \li Easing curve for a bounce (exponentially decaying parabolic bounce) function: decelerating to zero velocity.
\li \inlineimage qeasingcurve-outbounce.png
\row
\li \c Easing.InOutBounce
diff --git a/src/quick/util/qquickfontmetrics.cpp b/src/quick/util/qquickfontmetrics.cpp
index a87ec7d60a..0e3556be86 100644
--- a/src/quick/util/qquickfontmetrics.cpp
+++ b/src/quick/util/qquickfontmetrics.cpp
@@ -319,8 +319,7 @@ QRectF QQuickFontMetrics::tightBoundingRect(const QString &text) const
}
/*!
- \qmlmethod string QtQuick::FontMetrics::elidedText(string text, enum mode,
- qreal width, int flags)
+ \qmlmethod string QtQuick::FontMetrics::elidedText(string text, enumeration mode, real width, int flags)
This method returns a returns an elided version of the string (i.e., a
string with "..." in it) if the string \a text is wider than \a width.
diff --git a/src/quick/util/qquicktextmetrics.cpp b/src/quick/util/qquicktextmetrics.cpp
index 1dd787f4a5..13ccb515ce 100644
--- a/src/quick/util/qquicktextmetrics.cpp
+++ b/src/quick/util/qquicktextmetrics.cpp
@@ -244,7 +244,7 @@ QRectF QQuickTextMetrics::tightBoundingRect() const
}
/*!
- \qmlmethod string QtQuick::TextMetrics::elidedText
+ \qmlproperty string QtQuick::TextMetrics::elidedText
This property holds an elided version of the string (i.e., a string with
"..." in it) if the string \l text is wider than \l elideWidth. If the
diff --git a/src/quick/util/qquicktransition.cpp b/src/quick/util/qquicktransition.cpp
index 5c1c34b62f..2eaf8261af 100644
--- a/src/quick/util/qquicktransition.cpp
+++ b/src/quick/util/qquicktransition.cpp
@@ -432,7 +432,7 @@ bool QQuickTransition::running() const
This property holds a list of the animations to be run for this transition.
- \snippet qml/dynamicscene/dynamicscene.qml top-level transitions
+ \snippet ../qml/dynamicscene/dynamicscene.qml top-level transitions
The top-level animations are run in parallel. To run them sequentially,
define them within a SequentialAnimation: