summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWarwick Allison <warwick.allison@nokia.com>2009-12-02 05:47:29 (GMT)
committerWarwick Allison <warwick.allison@nokia.com>2009-12-02 05:47:29 (GMT)
commitd9735849834a5efc638dd026d6fe51d15dc528ee (patch)
tree3313bf43000feffb4cffe4e1f119fda45c60877f
parent289645d2bf46c1d6eace7a0d60389a9c10dd0c34 (diff)
parentdd0959ed872bf0cda7ad88382abce0c4b20bbdea (diff)
downloadQt-d9735849834a5efc638dd026d6fe51d15dc528ee.zip
Qt-d9735849834a5efc638dd026d6fe51d15dc528ee.tar.gz
Qt-d9735849834a5efc638dd026d6fe51d15dc528ee.tar.bz2
Merge branch 'kinetic-declarativeui' of git@scm.dev.nokia.troll.no:qt/kinetic into kinetic-declarativeui
Conflicts: src/declarative/qml/qmlmetatype.cpp
-rw-r--r--examples/declarative/loader/loader.pro2
-rw-r--r--examples/declarative/loader/qlistmodelinterface.h85
-rw-r--r--examples/declarative/loader/qmlfolderlistmodel.h2
-rw-r--r--examples/declarative/workerscript/workerscript.js16
-rw-r--r--examples/declarative/workerscript/workerscript.qml6
-rw-r--r--src/declarative/graphicsitems/qmlgraphicsflickable.cpp41
-rw-r--r--src/declarative/graphicsitems/qmlgraphicsflickable_p.h8
-rw-r--r--src/declarative/graphicsitems/qmlgraphicsflickable_p_p.h1
-rw-r--r--src/declarative/graphicsitems/qmlgraphicsgridview.cpp8
-rw-r--r--src/declarative/graphicsitems/qmlgraphicslistview.cpp10
-rw-r--r--src/declarative/qml/qmlboundsignal.cpp22
-rw-r--r--src/declarative/qml/qmlboundsignal_p.h4
-rw-r--r--src/declarative/qml/qmlcompileddata.cpp3
-rw-r--r--src/declarative/qml/qmlcompiler.cpp18
-rw-r--r--src/declarative/qml/qmlcompiler_p.h3
-rw-r--r--src/declarative/qml/qmlcomponent.cpp2
-rw-r--r--src/declarative/qml/qmlcontextscriptclass.cpp33
-rw-r--r--src/declarative/qml/qmlcontextscriptclass_p.h1
-rw-r--r--src/declarative/qml/qmlengine.cpp8
-rw-r--r--src/declarative/qml/qmlengine_p.h2
-rw-r--r--src/declarative/qml/qmlexpression.cpp56
-rw-r--r--src/declarative/qml/qmlexpression_p.h2
-rw-r--r--src/declarative/qml/qmlmetatype.cpp8
-rw-r--r--src/declarative/qml/qmlobjectscriptclass.cpp8
-rw-r--r--src/declarative/qml/qmlpropertycache.cpp4
-rw-r--r--src/declarative/qml/qmlpropertycache_p.h3
-rw-r--r--src/declarative/qml/qmlrewrite.cpp16
-rw-r--r--src/declarative/qml/qmlrewrite_p.h11
-rw-r--r--src/declarative/qml/qmlworkerscript.cpp359
-rw-r--r--src/declarative/qml/qmlworkerscript_p.h30
-rw-r--r--tests/benchmarks/declarative/qmltime/example.qml14
-rw-r--r--tests/benchmarks/declarative/qmltime/qmltime.cpp133
-rw-r--r--tests/benchmarks/declarative/qmltime/qmltime.pro8
33 files changed, 641 insertions, 286 deletions
diff --git a/examples/declarative/loader/loader.pro b/examples/declarative/loader/loader.pro
index edd6267..84b2d21 100644
--- a/examples/declarative/loader/loader.pro
+++ b/examples/declarative/loader/loader.pro
@@ -1,5 +1,5 @@
SOURCES = main.cpp qmlfolderlistmodel.cpp
-HEADERS = qmlfolderlistmodel.h qlistmodelinterface.h
+HEADERS = qmlfolderlistmodel.h
RESOURCES = loader.qrc
QT += script declarative network
diff --git a/examples/declarative/loader/qlistmodelinterface.h b/examples/declarative/loader/qlistmodelinterface.h
deleted file mode 100644
index 738378e..0000000
--- a/examples/declarative/loader/qlistmodelinterface.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: Qt Software Information (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
-**
-** 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 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain
-** additional rights. These rights are described in the Nokia Qt LGPL
-** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at qt-sales@nokia.com.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QLISTMODELINTERFACE_H
-#define QLISTMODELINTERFACE_H
-
-#include <QtCore/QHash>
-#include <QtCore/QVariant>
-
-
-QT_BEGIN_HEADER
-
-QT_BEGIN_NAMESPACE
-
-QT_MODULE(Declarative)
-
-class Q_DECLARATIVE_EXPORT QListModelInterface : public QObject
-{
- Q_OBJECT
- public:
- QListModelInterface(QObject *parent = 0) : QObject(parent) {}
- virtual ~QListModelInterface() {}
-
- virtual int count() const = 0;
- virtual QHash<int,QVariant> data(int index, const QList<int>& roles = QList<int>()) const = 0;
- virtual bool setData(int index, const QHash<int,QVariant>& values)
- { Q_UNUSED(index); Q_UNUSED(values); return false; }
-
- virtual QList<int> roles() const = 0;
- virtual QString toString(int role) const = 0;
-
- Q_SIGNALS:
- void itemsInserted(int index, int count);
- void itemsRemoved(int index, int count);
- void itemsMoved(int from, int to, int count);
- void itemsChanged(int index, int count, const QList<int> &roles);
-
- protected:
- QListModelInterface(QObjectPrivate &dd, QObject *parent)
- : QObject(dd, parent) {}
-};
-
-
-QT_END_NAMESPACE
-
-QT_END_HEADER
-#endif //QTREEMODELINTERFACE_H
diff --git a/examples/declarative/loader/qmlfolderlistmodel.h b/examples/declarative/loader/qmlfolderlistmodel.h
index f50719a..ac9568f 100644
--- a/examples/declarative/loader/qmlfolderlistmodel.h
+++ b/examples/declarative/loader/qmlfolderlistmodel.h
@@ -43,7 +43,7 @@
#define QMLFOLDERLISTMODEL_H
#include <qml.h>
-#include "qlistmodelinterface.h"
+#include "../../../src/declarative/3rdparty/qlistmodelinterface_p.h"
class QmlContext;
class QModelIndex;
diff --git a/examples/declarative/workerscript/workerscript.js b/examples/declarative/workerscript/workerscript.js
index 060c04a..f76471f 100644
--- a/examples/declarative/workerscript/workerscript.js
+++ b/examples/declarative/workerscript/workerscript.js
@@ -1,5 +1,15 @@
-onmessage = function(message) {
- print ("You clicked the " + message.rectangle + " rectangle.");
- print ("The coordinates were: " + message.x + "," + message.y);
+var lastx = 0;
+var lasty = 0;
+
+WorkerScript.onMessage = function(message) {
+ var ydiff = message.y - lasty;
+ var xdiff = message.x - lastx;
+
+ var total = Math.sqrt(ydiff * ydiff + xdiff * xdiff);
+
+ lastx = message.x;
+ lasty = message.y;
+
+ WorkerScript.sendMessage( {xmove: xdiff, ymove: ydiff, move: total} );
}
diff --git a/examples/declarative/workerscript/workerscript.qml b/examples/declarative/workerscript/workerscript.qml
index 3729022..e36d4d4 100644
--- a/examples/declarative/workerscript/workerscript.qml
+++ b/examples/declarative/workerscript/workerscript.qml
@@ -6,6 +6,12 @@ Rectangle {
WorkerScript {
id: myWorker
source: "workerscript.js"
+
+ onMessage: {
+ print("Moved " + messageObject.xmove + " along the X axis.");
+ print("Moved " + messageObject.ymove + " along the Y axis.");
+ print("Moved " + messageObject.move + " pixels.");
+ }
}
Rectangle {
diff --git a/src/declarative/graphicsitems/qmlgraphicsflickable.cpp b/src/declarative/graphicsitems/qmlgraphicsflickable.cpp
index e010081..d827cda 100644
--- a/src/declarative/graphicsitems/qmlgraphicsflickable.cpp
+++ b/src/declarative/graphicsitems/qmlgraphicsflickable.cpp
@@ -162,6 +162,7 @@ QmlGraphicsFlickablePrivate::QmlGraphicsFlickablePrivate()
, interactive(true), deceleration(500), maxVelocity(5000), reportedVelocitySmoothing(100)
, delayedPressEvent(0), delayedPressTarget(0), pressDelay(0)
, horizontalVelocity(this), verticalVelocity(this), vTime(0), visibleArea(0)
+ , flickDirection(QmlGraphicsFlickable::AutoFlickDirection)
{
fixupXEvent = QmlTimeLineEvent::timeLineEvent<QmlGraphicsFlickablePrivate, &QmlGraphicsFlickablePrivate::fixupX>(&_moveX, this);
fixupYEvent = QmlTimeLineEvent::timeLineEvent<QmlGraphicsFlickablePrivate, &QmlGraphicsFlickablePrivate::fixupY>(&_moveY, this);
@@ -576,6 +577,36 @@ QmlGraphicsFlickableVisibleArea *QmlGraphicsFlickable::visibleArea()
return d->visibleArea;
}
+/*!
+ \qmlproperty enumeration Flickable::flickDirection
+
+ This property determines which directions the view can be flicked.
+
+ \list
+ \o AutoFlickDirection (default) - allows flicking vertically if the
+ \e viewportHeight is not equal to the \e height of the Flickable.
+ Allows flicking horizontally if the \e viewportWidth is not equal
+ to the \e width of the Flickable.
+ \o HorizontalFlick - allows flicking horizontally.
+ \o VerticalFlick - allows flicking vertically.
+ \o HorizontalAndVerticalFlick - allows flicking in both directions.
+ \endlist
+*/
+QmlGraphicsFlickable::FlickDirection QmlGraphicsFlickable::flickDirection() const
+{
+ Q_D(const QmlGraphicsFlickable);
+ return d->flickDirection;
+}
+
+void QmlGraphicsFlickable::setFlickDirection(FlickDirection direction)
+{
+ Q_D(QmlGraphicsFlickable);
+ if (direction != d->flickDirection) {
+ d->flickDirection = direction;
+ emit flickDirectionChanged();
+ }
+}
+
void QmlGraphicsFlickablePrivate::handleMousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (interactive && timeline.isActive() && (qAbs(velocityX) > 10 || qAbs(velocityY) > 10))
@@ -1039,12 +1070,18 @@ qreal QmlGraphicsFlickable::vHeight() const
bool QmlGraphicsFlickable::xflick() const
{
- return vWidth() != width();
+ Q_D(const QmlGraphicsFlickable);
+ if (d->flickDirection == QmlGraphicsFlickable::AutoFlickDirection)
+ return vWidth() != width();
+ return d->flickDirection & QmlGraphicsFlickable::HorizontalFlick;
}
bool QmlGraphicsFlickable::yflick() const
{
- return vHeight() != height();
+ Q_D(const QmlGraphicsFlickable);
+ if (d->flickDirection == QmlGraphicsFlickable::AutoFlickDirection)
+ return vHeight() != height();
+ return d->flickDirection & QmlGraphicsFlickable::VerticalFlick;
}
bool QmlGraphicsFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event)
diff --git a/src/declarative/graphicsitems/qmlgraphicsflickable_p.h b/src/declarative/graphicsitems/qmlgraphicsflickable_p.h
index 50248e1..9610ac1 100644
--- a/src/declarative/graphicsitems/qmlgraphicsflickable_p.h
+++ b/src/declarative/graphicsitems/qmlgraphicsflickable_p.h
@@ -70,6 +70,7 @@ class Q_DECLARATIVE_EXPORT QmlGraphicsFlickable : public QmlGraphicsItem
Q_PROPERTY(qreal flickDeceleration READ flickDeceleration WRITE setFlickDeceleration)
Q_PROPERTY(bool moving READ isMoving NOTIFY movingChanged)
Q_PROPERTY(bool flicking READ isFlicking NOTIFY flickingChanged)
+ Q_PROPERTY(FlickDirection flickDirection READ flickDirection WRITE setFlickDirection NOTIFY flickDirectionChanged)
Q_PROPERTY(bool interactive READ isInteractive WRITE setInteractive)
Q_PROPERTY(int pressDelay READ pressDelay WRITE setPressDelay)
@@ -85,6 +86,8 @@ class Q_DECLARATIVE_EXPORT QmlGraphicsFlickable : public QmlGraphicsItem
Q_PROPERTY(QmlList<QmlGraphicsItem *>* flickableChildren READ flickableChildren)
Q_CLASSINFO("DefaultProperty", "flickableData")
+ Q_ENUMS(FlickDirection)
+
public:
QmlGraphicsFlickable(QmlGraphicsItem *parent=0);
~QmlGraphicsFlickable();
@@ -135,6 +138,10 @@ public:
QmlGraphicsItem *viewport();
+ enum FlickDirection { AutoFlickDirection=0x00, HorizontalFlick=0x01, VerticalFlick=0x02, HorizontalAndVerticalFlick=0x03 };
+ FlickDirection flickDirection() const;
+ void setFlickDirection(FlickDirection);
+
Q_SIGNALS:
void viewportWidthChanged();
void viewportHeightChanged();
@@ -151,6 +158,7 @@ Q_SIGNALS:
void verticalVelocityChanged();
void isAtBoundaryChanged();
void pageChanged();
+ void flickDirectionChanged();
protected:
virtual bool sceneEventFilter(QGraphicsItem *, QEvent *);
diff --git a/src/declarative/graphicsitems/qmlgraphicsflickable_p_p.h b/src/declarative/graphicsitems/qmlgraphicsflickable_p_p.h
index 210052e..104769d 100644
--- a/src/declarative/graphicsitems/qmlgraphicsflickable_p_p.h
+++ b/src/declarative/graphicsitems/qmlgraphicsflickable_p_p.h
@@ -134,6 +134,7 @@ public:
int vTime;
QmlTimeLine velocityTimeline;
QmlGraphicsFlickableVisibleArea *visibleArea;
+ QmlGraphicsFlickable::FlickDirection flickDirection;
void handleMousePressEvent(QGraphicsSceneMouseEvent *);
void handleMouseMoveEvent(QGraphicsSceneMouseEvent *);
diff --git a/src/declarative/graphicsitems/qmlgraphicsgridview.cpp b/src/declarative/graphicsitems/qmlgraphicsgridview.cpp
index f223413..cb6e675 100644
--- a/src/declarative/graphicsitems/qmlgraphicsgridview.cpp
+++ b/src/declarative/graphicsitems/qmlgraphicsgridview.cpp
@@ -327,6 +327,7 @@ void QmlGraphicsGridViewPrivate::init()
q->setFlag(QGraphicsItem::ItemIsFocusScope);
QObject::connect(q, SIGNAL(widthChanged()), q, SLOT(sizeChange()));
QObject::connect(q, SIGNAL(heightChanged()), q, SLOT(sizeChange()));
+ q->setFlickDirection(QmlGraphicsFlickable::VerticalFlick);
}
void QmlGraphicsGridViewPrivate::clear()
@@ -1014,10 +1015,13 @@ void QmlGraphicsGridView::setFlow(Flow flow)
Q_D(QmlGraphicsGridView);
if (d->flow != flow) {
d->flow = flow;
- if (d->flow == LeftToRight)
+ if (d->flow == LeftToRight) {
setViewportWidth(-1);
- else
+ setFlickDirection(QmlGraphicsFlickable::VerticalFlick);
+ } else {
setViewportHeight(-1);
+ setFlickDirection(QmlGraphicsFlickable::HorizontalFlick);
+ }
d->clear();
d->updateGrid();
refill();
diff --git a/src/declarative/graphicsitems/qmlgraphicslistview.cpp b/src/declarative/graphicsitems/qmlgraphicslistview.cpp
index c4edbb7..eb7a026 100644
--- a/src/declarative/graphicsitems/qmlgraphicslistview.cpp
+++ b/src/declarative/graphicsitems/qmlgraphicslistview.cpp
@@ -490,6 +490,7 @@ void QmlGraphicsListViewPrivate::init()
QObject::connect(q, SIGNAL(heightChanged()), q, SLOT(refill()));
QObject::connect(q, SIGNAL(widthChanged()), q, SLOT(refill()));
QObject::connect(q, SIGNAL(movementEnded()), q, SLOT(animStopped()));
+ q->setFlickDirection(QmlGraphicsFlickable::VerticalFlick);
}
void QmlGraphicsListViewPrivate::clear()
@@ -1667,10 +1668,13 @@ void QmlGraphicsListView::setOrientation(QmlGraphicsListView::Orientation orient
Q_D(QmlGraphicsListView);
if (d->orient != orientation) {
d->orient = orientation;
- if (d->orient == QmlGraphicsListView::Vertical)
+ if (d->orient == QmlGraphicsListView::Vertical) {
setViewportWidth(-1);
- else
+ setFlickDirection(VerticalFlick);
+ } else {
setViewportHeight(-1);
+ setFlickDirection(HorizontalFlick);
+ }
d->clear();
refill();
emit orientationChanged();
@@ -2131,6 +2135,8 @@ void QmlGraphicsListView::trackedPositionChanged()
pos = d->startPosition();
} else if (d->trackedItem->endPosition() > d->endPosition() - d->size() + d->highlightRangeEnd) {
pos = d->endPosition() - d->size();
+ if (pos < d->startPosition())
+ pos = d->startPosition();
} else {
if (trackedPos < viewPos + d->highlightRangeStart) {
pos = trackedPos - d->highlightRangeStart;
diff --git a/src/declarative/qml/qmlboundsignal.cpp b/src/declarative/qml/qmlboundsignal.cpp
index 4a0577a..78bcd49 100644
--- a/src/declarative/qml/qmlboundsignal.cpp
+++ b/src/declarative/qml/qmlboundsignal.cpp
@@ -93,7 +93,7 @@ QmlAbstractBoundSignal::~QmlAbstractBoundSignal()
QmlBoundSignal::QmlBoundSignal(QObject *scope, const QMetaMethod &signal,
QObject *parent)
-: m_expression(0), m_idx(signal.methodIndex()), m_params(0)
+: m_expression(0), m_signal(signal), m_paramsValid(false), m_params(0)
{
// A cached evaluation of the QmlExpression::value() slot index.
//
@@ -103,16 +103,13 @@ QmlBoundSignal::QmlBoundSignal(QObject *scope, const QMetaMethod &signal,
if (evaluateIdx == -1) evaluateIdx = metaObject()->methodCount();
QmlGraphics_setParent_noEvent(this, parent);
- QMetaObject::connect(scope, m_idx, this, evaluateIdx);
-
- if (!signal.parameterTypes().isEmpty())
- m_params = new QmlBoundSignalParameters(signal, this);
+ QMetaObject::connect(scope, m_signal.methodIndex(), this, evaluateIdx);
}
QmlBoundSignal::QmlBoundSignal(QmlContext *ctxt, const QString &val,
QObject *scope, const QMetaMethod &signal,
QObject *parent)
-: m_expression(0), m_idx(signal.methodIndex()), m_params(0)
+: m_expression(0), m_signal(signal), m_paramsValid(false), m_params(0)
{
// A cached evaluation of the QmlExpression::value() slot index.
//
@@ -122,13 +119,10 @@ QmlBoundSignal::QmlBoundSignal(QmlContext *ctxt, const QString &val,
if (evaluateIdx == -1) evaluateIdx = metaObject()->methodCount();
QmlGraphics_setParent_noEvent(this, parent);
- QMetaObject::connect(scope, m_idx, this, evaluateIdx);
+ QMetaObject::connect(scope, m_signal.methodIndex(), this, evaluateIdx);
m_expression = new QmlExpression(ctxt, val, scope);
m_expression->setTrackChange(false);
-
- if (!signal.parameterTypes().isEmpty())
- m_params = new QmlBoundSignalParameters(signal, this);
}
QmlBoundSignal::~QmlBoundSignal()
@@ -139,7 +133,7 @@ QmlBoundSignal::~QmlBoundSignal()
int QmlBoundSignal::index() const
{
- return m_idx;
+ return m_signal.methodIndex();
}
/*!
@@ -174,6 +168,12 @@ QmlBoundSignal *QmlBoundSignal::cast(QObject *o)
int QmlBoundSignal::qt_metacall(QMetaObject::Call c, int id, void **a)
{
if (c == QMetaObject::InvokeMetaMethod && id == evaluateIdx) {
+ if (!m_paramsValid) {
+ if (!m_signal.parameterTypes().isEmpty())
+ m_params = new QmlBoundSignalParameters(m_signal, this);
+ m_paramsValid = true;
+ }
+
if (m_params) m_params->setValues(a);
if (m_expression) {
QmlExpressionPrivate::get(m_expression)->value(m_params);
diff --git a/src/declarative/qml/qmlboundsignal_p.h b/src/declarative/qml/qmlboundsignal_p.h
index e801892..53a5a6b 100644
--- a/src/declarative/qml/qmlboundsignal_p.h
+++ b/src/declarative/qml/qmlboundsignal_p.h
@@ -55,6 +55,7 @@
#include <qmlexpression.h>
#include <private/qobject_p.h>
+#include <QtCore/qmetaobject.h>
QT_BEGIN_NAMESPACE
@@ -87,7 +88,8 @@ protected:
private:
QmlExpression *m_expression;
- int m_idx;
+ QMetaMethod m_signal;
+ bool m_paramsValid;
QmlBoundSignalParameters *m_params;
};
diff --git a/src/declarative/qml/qmlcompileddata.cpp b/src/declarative/qml/qmlcompileddata.cpp
index 44d2745..9b931c5 100644
--- a/src/declarative/qml/qmlcompileddata.cpp
+++ b/src/declarative/qml/qmlcompileddata.cpp
@@ -167,7 +167,8 @@ QmlCompiledData::~QmlCompiledData()
if (importCache)
importCache->release();
- qDeleteAll(programs);
+ qDeleteAll(cachedPrograms);
+ qDeleteAll(cachedClosures);
}
QObject *QmlCompiledData::TypeReference::createInstance(QmlContext *ctxt, const QBitField &bindings) const
diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp
index ee0c484..8edf023 100644
--- a/src/declarative/qml/qmlcompiler.cpp
+++ b/src/declarative/qml/qmlcompiler.cpp
@@ -2529,12 +2529,26 @@ bool QmlCompiler::completeComponentBuild()
// Pre-rewrite the expression
QString expression = binding.expression.asScript();
+
+ // ### Optimize
+ QmlRewrite::SharedBindingTester sharableTest;
+ bool isSharable = sharableTest.isSharable(expression);
+
QmlRewrite::RewriteBinding rewriteBinding;
expression = rewriteBinding(expression);
quint32 length = expression.length();
- quint32 pc = output->programs.length();
- output->programs.append(0);
+ quint32 pc;
+
+ if (isSharable) {
+ pc = output->cachedClosures.count();
+ pc |= 0x80000000;
+ output->cachedClosures.append(0);
+ } else {
+ pc = output->cachedPrograms.length();
+ output->cachedPrograms.append(0);
+ }
+
binding.compiledData =
QByteArray((const char *)&pc, sizeof(quint32)) +
QByteArray((const char *)&length, sizeof(quint32)) +
diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h
index 6b41a5f..991ae81 100644
--- a/src/declarative/qml/qmlcompiler_p.h
+++ b/src/declarative/qml/qmlcompiler_p.h
@@ -113,7 +113,8 @@ public:
QList<QByteArray> datas;
QList<QmlParser::Location> locations;
QList<QmlInstruction> bytecode;
- QList<QScriptProgram *> programs;
+ QList<QScriptProgram *> cachedPrograms;
+ QList<QScriptValue *> cachedClosures;
QList<QmlPropertyCache *> propertyCaches;
QList<QmlIntegerCache *> contextCaches;
QList<QmlParser::Object::ScriptBlock> scripts;
diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp
index 1e03557..2e8e4ce 100644
--- a/src/declarative/qml/qmlcomponent.cpp
+++ b/src/declarative/qml/qmlcomponent.cpp
@@ -705,7 +705,7 @@ void QmlComponentPrivate::completeCreate()
QmlEnginePrivate::SimpleList<QmlParserStatus> ps =
parserStatus.at(ii);
- for (int jj = 0; jj < ps.count; ++jj) {
+ for (int jj = ps.count - 1; jj >= 0; --jj) {
QmlParserStatus *status = ps.at(jj);
if (status && status->d) {
status->d = 0;
diff --git a/src/declarative/qml/qmlcontextscriptclass.cpp b/src/declarative/qml/qmlcontextscriptclass.cpp
index acf6203..c740ce7 100644
--- a/src/declarative/qml/qmlcontextscriptclass.cpp
+++ b/src/declarative/qml/qmlcontextscriptclass.cpp
@@ -47,9 +47,27 @@
QT_BEGIN_NAMESPACE
struct ContextData : public QScriptDeclarativeClass::Object {
- ContextData(QmlContext *c, QObject *o) : context(c), scopeObject(o) {}
+ ContextData() : isSharedContext(true) {}
+ ContextData(QmlContext *c, QObject *o) : context(c), scopeObject(o), isSharedContext(false) {}
QGuard<QmlContext> context;
QGuard<QObject> scopeObject;
+ bool isSharedContext;
+
+ QmlContext *getContext(QmlEngine *engine) {
+ if (isSharedContext) {
+ return QmlEnginePrivate::get(engine)->sharedContext;
+ } else {
+ return context.data();
+ }
+ }
+
+ QObject *getScope(QmlEngine *engine) {
+ if (isSharedContext) {
+ return QmlEnginePrivate::get(engine)->sharedScope;
+ } else {
+ return scopeObject.data();
+ }
+ }
};
/*
@@ -73,13 +91,20 @@ QScriptValue QmlContextScriptClass::newContext(QmlContext *context, QObject *sco
return newObject(scriptEngine, this, new ContextData(context, scopeObject));
}
+QScriptValue QmlContextScriptClass::newSharedContext()
+{
+ QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine);
+
+ return newObject(scriptEngine, this, new ContextData());
+}
+
QmlContext *QmlContextScriptClass::contextFromValue(const QScriptValue &v)
{
if (scriptClass(v) != this)
return 0;
ContextData *data = (ContextData *)object(v);
- return data->context;
+ return data->getContext(engine);
}
QScriptClass::QueryFlags
@@ -94,8 +119,8 @@ QmlContextScriptClass::queryProperty(Object *object, const Identifier &name,
lastPropertyIndex = -1;
lastDefaultObject = -1;
- QmlContext *bindContext = ((ContextData *)object)->context.data();
- QObject *scopeObject = ((ContextData *)object)->scopeObject.data();
+ QmlContext *bindContext = ((ContextData *)object)->getContext(engine);
+ QObject *scopeObject = ((ContextData *)object)->getScope(engine);
if (!bindContext)
return 0;
diff --git a/src/declarative/qml/qmlcontextscriptclass_p.h b/src/declarative/qml/qmlcontextscriptclass_p.h
index cf91242..d24dfa6 100644
--- a/src/declarative/qml/qmlcontextscriptclass_p.h
+++ b/src/declarative/qml/qmlcontextscriptclass_p.h
@@ -68,6 +68,7 @@ public:
~QmlContextScriptClass();
QScriptValue newContext(QmlContext *, QObject * = 0);
+ QScriptValue newSharedContext();
QmlContext *contextFromValue(const QScriptValue &);
diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp
index 0221458..f136017 100644
--- a/src/declarative/qml/qmlengine.cpp
+++ b/src/declarative/qml/qmlengine.cpp
@@ -110,7 +110,7 @@ struct StaticQtMetaObject : public QObject
QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e)
: rootContext(0), currentExpression(0),
- isDebugging(false), contextClass(0), objectClass(0), valueTypeClass(0), globalClass(0),
+ isDebugging(false), contextClass(0), sharedContext(0), sharedScope(0), objectClass(0), valueTypeClass(0), globalClass(0),
nodeListClass(0), namedNodeMapClass(0), sqlQueryClass(0), cleanup(0), erroredBindings(0),
inProgressCreations(0), scriptEngine(this), workerScriptEngine(0), componentAttacheds(0),
rootComponent(0), networkAccessManager(0), typeManager(e), uniqueId(1)
@@ -160,6 +160,10 @@ QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e)
scriptEngine.globalObject().setProperty(QLatin1String("createComponent"),
scriptEngine.newFunction(QmlEnginePrivate::createComponent, 1));
+ // translation functions need to be installed
+ // before the global script class is constructed (QTBUG-6437)
+ scriptEngine.installTranslatorFunctions();
+
globalClass = new QmlGlobalScriptClass(&scriptEngine);
}
@@ -226,8 +230,8 @@ void QmlEnginePrivate::init()
Q_Q(QmlEngine);
qRegisterMetaType<QVariant>("QVariant");
qRegisterMetaType<QmlScriptString>("QmlScriptString");
+ qRegisterMetaType<QScriptValue>("QScriptValue");
- scriptEngine.installTranslatorFunctions();
contextClass = new QmlContextScriptClass(q);
objectClass = new QmlObjectScriptClass(q);
valueTypeClass = new QmlValueTypeScriptClass(q);
diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h
index 93fe4a7..9267a66 100644
--- a/src/declarative/qml/qmlengine_p.h
+++ b/src/declarative/qml/qmlengine_p.h
@@ -126,6 +126,8 @@ public:
struct ImportedNamespace;
QmlContextScriptClass *contextClass;
+ QmlContext *sharedContext;
+ QObject *sharedScope;
QmlObjectScriptClass *objectClass;
QmlValueTypeScriptClass *valueTypeClass;
QmlTypeNameScriptClass *typeNameClass;
diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp
index d2d60ee..2239d77 100644
--- a/src/declarative/qml/qmlexpression.cpp
+++ b/src/declarative/qml/qmlexpression.cpp
@@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE
QmlExpressionData::QmlExpressionData()
: expressionFunctionValid(false), expressionRewritten(false), me(0),
- trackChange(true), line(-1), guardList(0), guardListLength(0)
+ trackChange(true), isShared(false), line(-1), guardList(0), guardListLength(0)
{
}
@@ -108,27 +108,47 @@ void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc,
data->expression = QString::fromRawData((QChar *)(exprData + 3), exprData[2]);
int progIdx = *(exprData + 1);
+ bool isShared = progIdx & 0x80000000;
+ progIdx &= 0x7FFFFFFF;
+
QmlEngine *engine = ctxt->engine();
QmlEnginePrivate *ep = QmlEnginePrivate::get(engine);
QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine);
+
+ if (isShared) {
+
+ if (!dd->cachedClosures.at(progIdx)) {
+ QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
+ scriptContext->pushScope(ep->contextClass->newSharedContext());
+ dd->cachedClosures[progIdx] = new QScriptValue(scriptEngine->evaluate(data->expression, data->url.toString(), data->line));
+ scriptEngine->popContext();
+ }
+
+ data->expressionFunction = *dd->cachedClosures.at(progIdx);
+ data->isShared = true;
+ data->expressionFunctionValid = true;
+
+ } else {
+
#if !defined(Q_OS_SYMBIAN) //XXX Why doesn't this work?
- if (!dd->programs.at(progIdx)) {
- dd->programs[progIdx] =
- new QScriptProgram(data->expression, data->url.toString(), data->line);
- }
+ if (!dd->cachedPrograms.at(progIdx)) {
+ dd->cachedPrograms[progIdx] =
+ new QScriptProgram(data->expression, data->url.toString(), data->line);
+ }
#endif
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
- scriptContext->pushScope(ep->contextClass->newContext(ctxt, me));
+ QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
+ scriptContext->pushScope(ep->contextClass->newContext(ctxt, me));
#if !defined(Q_OS_SYMBIAN)
- data->expressionFunction = scriptEngine->evaluate(*dd->programs[progIdx]);
+ data->expressionFunction = scriptEngine->evaluate(*dd->cachedPrograms.at(progIdx));
#else
- data->expressionFunction = scriptEngine->evaluate(data->expression);
+ data->expressionFunction = scriptEngine->evaluate(data->expression);
#endif
- data->expressionFunctionValid = true;
- scriptEngine->popContext();
+ data->expressionFunctionValid = true;
+ scriptEngine->popContext();
+ }
}
data->QmlAbstractExpression::setContext(ctxt);
@@ -328,8 +348,22 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope, bool *isUnd
data->expressionFunctionValid = true;
}
+ QmlContext *oldSharedContext = 0;
+ QObject *oldSharedScope = 0;
+ if (data->isShared) {
+ oldSharedContext = ep->sharedContext;
+ oldSharedScope = ep->sharedScope;
+ ep->sharedContext = data->context();
+ ep->sharedScope = data->me;
+ }
+
QScriptValue svalue = data->expressionFunction.call();
+ if (data->isShared) {
+ ep->sharedContext = oldSharedContext;
+ ep->sharedScope = oldSharedScope;
+ }
+
if (isUndefined)
*isUndefined = svalue.isUndefined() || scriptEngine->hasUncaughtException();
diff --git a/src/declarative/qml/qmlexpression_p.h b/src/declarative/qml/qmlexpression_p.h
index c6ba54d..dbb12ba 100644
--- a/src/declarative/qml/qmlexpression_p.h
+++ b/src/declarative/qml/qmlexpression_p.h
@@ -101,6 +101,8 @@ public:
QObject *me;
bool trackChange;
+ bool isShared;
+
QUrl url;
int line;
diff --git a/src/declarative/qml/qmlmetatype.cpp b/src/declarative/qml/qmlmetatype.cpp
index 5172152..06927457 100644
--- a/src/declarative/qml/qmlmetatype.cpp
+++ b/src/declarative/qml/qmlmetatype.cpp
@@ -58,6 +58,7 @@
#include <qlocale.h>
#include <ctype.h>
#include <QtCore/qcryptographichash.h>
+#include <QtScript/qscriptvalue.h>
#include "qmlcustomparser_p.h"
#ifdef QT_BOOTSTRAPPED
@@ -929,6 +930,7 @@ QList<QmlType*> QmlMetaType::qmlTypes()
#include <QtGui/qvector3d.h>
#include <QtGui/qvector4d.h>
#include <QtGui/qquaternion.h>
+Q_DECLARE_METATYPE(QScriptValue);
/*!
Copies \a copy into \a data, assuming they both are of type \a type. If
@@ -1138,6 +1140,9 @@ bool QmlMetaType::copy(int type, void *data, const void *copy)
if (type == qMetaTypeId<QVariant>()) {
*static_cast<NS(QVariant) *>(data) = *static_cast<const NS(QVariant)*>(copy);
return true;
+ } else if (type == qMetaTypeId<QScriptValue>()) {
+ *static_cast<NS(QScriptValue) *>(data) = *static_cast<const NS(QScriptValue)*>(copy);
+ return true;
} else if (typeCategory(type) != Unknown) {
*static_cast<void **>(data) = *static_cast<void* const *>(copy);
return true;
@@ -1340,6 +1345,9 @@ bool QmlMetaType::copy(int type, void *data, const void *copy)
if (type == qMetaTypeId<QVariant>()) {
*static_cast<NS(QVariant) *>(data) = NS(QVariant)();
return true;
+ } else if (type == qMetaTypeId<QScriptValue>()) {
+ *static_cast<NS(QScriptValue) *>(data) = NS(QScriptValue)();
+ return true;
} else if (typeCategory(type) != Unknown) {
*static_cast<void **>(data) = 0;
return true;
diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp
index 5110ea0..7c4ce5b 100644
--- a/src/declarative/qml/qmlobjectscriptclass.cpp
+++ b/src/declarative/qml/qmlobjectscriptclass.cpp
@@ -229,12 +229,16 @@ QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name
} else if (lastData->flags & QmlPropertyCache::Data::IsQmlList) {
return enginePriv->listClass->newList(obj, lastData->coreIndex,
QmlListScriptClass::QmlListPtr);
- } if (lastData->flags & QmlPropertyCache::Data::IsQObjectDerived) {
+ } else if (lastData->flags & QmlPropertyCache::Data::IsQObjectDerived) {
QObject *rv = 0;
void *args[] = { &rv, 0 };
QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
-
return newQObject(rv, lastData->propType);
+ } else if (lastData->flags & QmlPropertyCache::Data::IsQScriptValue) {
+ QScriptValue rv = scriptEngine->nullValue();
+ void *args[] = { &rv, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
+ return rv;
} else {
QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj);
return enginePriv->scriptValueFromVariant(var);
diff --git a/src/declarative/qml/qmlpropertycache.cpp b/src/declarative/qml/qmlpropertycache.cpp
index c5cdbaa..0e7da84 100644
--- a/src/declarative/qml/qmlpropertycache.cpp
+++ b/src/declarative/qml/qmlpropertycache.cpp
@@ -45,6 +45,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_METATYPE(QScriptValue);
+
void QmlPropertyCache::Data::load(const QMetaProperty &p)
{
propType = p.userType();
@@ -61,6 +63,8 @@ void QmlPropertyCache::Data::load(const QMetaProperty &p)
if (propType == qMetaTypeId<QmlBinding *>()) {
flags |= Data::IsQmlBinding;
+ } else if (propType == qMetaTypeId<QScriptValue>()) {
+ flags |= Data::IsQScriptValue;
} else if (p.isEnumType()) {
flags |= Data::IsEnumType;
} else {
diff --git a/src/declarative/qml/qmlpropertycache_p.h b/src/declarative/qml/qmlpropertycache_p.h
index 28dd66d..9265910 100644
--- a/src/declarative/qml/qmlpropertycache_p.h
+++ b/src/declarative/qml/qmlpropertycache_p.h
@@ -83,7 +83,8 @@ public:
IsEnumType = 0x00000010,
IsQmlList = 0x00000020,
IsQList = 0x00000040,
- IsQmlBinding = 0x00000080
+ IsQmlBinding = 0x00000080,
+ IsQScriptValue = 0x00000100
};
Q_DECLARE_FLAGS(Flags, Flag)
diff --git a/src/declarative/qml/qmlrewrite.cpp b/src/declarative/qml/qmlrewrite.cpp
index dc90255..5fcebf4d 100644
--- a/src/declarative/qml/qmlrewrite.cpp
+++ b/src/declarative/qml/qmlrewrite.cpp
@@ -49,6 +49,22 @@ DEFINE_BOOL_CONFIG_OPTION(rewriteDump, QML_REWRITE_DUMP);
namespace QmlRewrite {
+bool SharedBindingTester::isSharable(const QString &code)
+{
+ Engine engine;
+ NodePool pool(QString(), &engine);
+ Lexer lexer(&engine);
+ Parser parser(&engine);
+ lexer.setCode(code, 0);
+ parser.parseStatement();
+ if (!parser.statement())
+ return false;
+
+ _sharable = true;
+ AST::Node::acceptChild(parser.statement(), this);
+ return _sharable;
+}
+
QString RewriteBinding::operator()(const QString &code, bool *ok)
{
Engine engine;
diff --git a/src/declarative/qml/qmlrewrite_p.h b/src/declarative/qml/qmlrewrite_p.h
index a5cb841..a04a0db 100644
--- a/src/declarative/qml/qmlrewrite_p.h
+++ b/src/declarative/qml/qmlrewrite_p.h
@@ -63,6 +63,17 @@ QT_BEGIN_NAMESPACE
namespace QmlRewrite {
using namespace QmlJS;
+class SharedBindingTester : protected AST::Visitor
+{
+ bool _sharable;
+public:
+ bool isSharable(const QString &code);
+
+ virtual bool visit(AST::FunctionDeclaration *) { _sharable = false; return false; }
+ virtual bool visit(AST::FunctionExpression *) { _sharable = false; return false; }
+ virtual bool visit(AST::CallExpression *) { _sharable = false; return false; }
+};
+
class RewriteBinding: protected AST::Visitor
{
unsigned _position;
diff --git a/src/declarative/qml/qmlworkerscript.cpp b/src/declarative/qml/qmlworkerscript.cpp
index 75c67cc..a41d9c5 100644
--- a/src/declarative/qml/qmlworkerscript.cpp
+++ b/src/declarative/qml/qmlworkerscript.cpp
@@ -55,15 +55,15 @@ class WorkerDataEvent : public QEvent
public:
enum Type { WorkerData = QEvent::User };
- WorkerDataEvent(int workerId, QmlWorkerScriptEngine::Data *data);
+ WorkerDataEvent(int workerId, const QVariant &data);
virtual ~WorkerDataEvent();
int workerId() const;
- QmlWorkerScriptEngine::Data *takeData();
+ QVariant data() const;
private:
int m_id;
- QmlWorkerScriptEngine::Data *m_data;
+ QVariant m_data;
};
class WorkerLoadEvent : public QEvent
@@ -81,31 +81,64 @@ private:
QUrl m_url;
};
+class WorkerRemoveEvent : public QEvent
+{
+public:
+ enum Type { WorkerRemove = WorkerLoadEvent::WorkerLoad + 1 };
+
+ WorkerRemoveEvent(int workerId);
+
+ int workerId() const;
+
+private:
+ int m_id;
+};
+
class QmlWorkerScriptEnginePrivate : public QObject
{
public:
QmlWorkerScriptEnginePrivate();
- QScriptEngine *workerEngine;
+ struct ScriptEngine : public QScriptEngine
+ {
+ ScriptEngine(QmlWorkerScriptEnginePrivate *parent) : p(parent) {}
+ QmlWorkerScriptEnginePrivate *p;
+ };
+ ScriptEngine *workerEngine;
+ static QmlWorkerScriptEnginePrivate *get(QScriptEngine *e) {
+ return static_cast<ScriptEngine *>(e)->p;
+ }
QMutex m_lock;
QWaitCondition m_wait;
+ struct WorkerScript {
+ WorkerScript();
+
+ int id;
+ bool initialized;
+ QmlWorkerScript *owner;
+ QScriptValue object;
+
+ QScriptValue callback;
+ };
+
+ QHash<int, WorkerScript *> workers;
QScriptValue getWorker(int);
int m_nextId;
- QHash<int, QScriptValue> m_workers;
static QVariant scriptValueToVariant(const QScriptValue &);
static QScriptValue variantToScriptValue(const QVariant &, QScriptEngine *);
- static QScriptValue onmessage(QScriptContext *ctxt, QScriptEngine *engine);
+ static QScriptValue onMessage(QScriptContext *ctxt, QScriptEngine *engine);
+ static QScriptValue sendMessage(QScriptContext *ctxt, QScriptEngine *engine);
protected:
virtual bool event(QEvent *);
private:
- void processMessage(int, QmlWorkerScriptEngine::Data *);
+ void processMessage(int, const QVariant &);
void processLoad(int, const QUrl &);
};
@@ -114,34 +147,75 @@ QmlWorkerScriptEnginePrivate::QmlWorkerScriptEnginePrivate()
{
}
-QScriptValue QmlWorkerScriptEnginePrivate::onmessage(QScriptContext *ctxt, QScriptEngine *engine)
+QScriptValue QmlWorkerScriptEnginePrivate::onMessage(QScriptContext *ctxt, QScriptEngine *engine)
{
+ QmlWorkerScriptEnginePrivate *p = QmlWorkerScriptEnginePrivate::get(engine);
+
+ int id = ctxt->thisObject().data().toVariant().toInt();
+
+ WorkerScript *script = p->workers.value(id);
+ if (!script)
+ return engine->undefinedValue();
+
if (ctxt->argumentCount() >= 1)
- ctxt->thisObject().setData(ctxt->argument(0));
+ script->callback = ctxt->argument(0);
+
+ return script->callback;
+}
+
+QScriptValue QmlWorkerScriptEnginePrivate::sendMessage(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ if (!ctxt->argumentCount())
+ return engine->undefinedValue();
+
+ QmlWorkerScriptEnginePrivate *p = QmlWorkerScriptEnginePrivate::get(engine);
+
+ int id = ctxt->thisObject().data().toVariant().toInt();
+
+ WorkerScript *script = p->workers.value(id);
+ if (!script)
+ return engine->undefinedValue();
- return ctxt->thisObject().data();
+ p->m_lock.lock();
+ if (script->owner)
+ QCoreApplication::postEvent(script->owner,
+ new WorkerDataEvent(0, scriptValueToVariant(ctxt->argument(0))));
+ p->m_lock.unlock();
+
+ return engine->undefinedValue();
}
QScriptValue QmlWorkerScriptEnginePrivate::getWorker(int id)
{
- QHash<int, QScriptValue>::Iterator iter = m_workers.find(id);
- if (iter == m_workers.end()) {
- QScriptValue worker = workerEngine->newObject();
+ QHash<int, WorkerScript *>::ConstIterator iter = workers.find(id);
+
+ if (iter == workers.end())
+ return workerEngine->nullValue();
+
+ WorkerScript *script = *iter;
+ if (!script->initialized) {
- worker.setProperty(QLatin1String("onmessage"), workerEngine->newFunction(onmessage),
- QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ script->initialized = true;
+ script->object = workerEngine->newObject();
- iter = m_workers.insert(id, worker);
+ QScriptValue api = workerEngine->newObject();
+ api.setData(script->id);
+
+ api.setProperty(QLatin1String("onMessage"), workerEngine->newFunction(onMessage),
+ QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ api.setProperty(QLatin1String("sendMessage"), workerEngine->newFunction(sendMessage));
+
+ script->object.setProperty(QLatin1String("WorkerScript"), api);
}
- return *iter;
+ return script->object;
}
bool QmlWorkerScriptEnginePrivate::event(QEvent *event)
{
if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
- processMessage(workerEvent->workerId(), workerEvent->takeData());
+ processMessage(workerEvent->workerId(), workerEvent->data());
return true;
} else if (event->type() == (QEvent::Type)WorkerLoadEvent::WorkerLoad) {
WorkerLoadEvent *workerEvent = static_cast<WorkerLoadEvent *>(event);
@@ -152,19 +226,18 @@ bool QmlWorkerScriptEnginePrivate::event(QEvent *event)
}
}
-void QmlWorkerScriptEnginePrivate::processMessage(int id, QmlWorkerScriptEngine::Data *data)
+void QmlWorkerScriptEnginePrivate::processMessage(int id, const QVariant &data)
{
- QScriptValue worker = getWorker(id);
- QScriptValue onmessage = worker.data();
+ WorkerScript *script = workers.value(id);
+ if (!script)
+ return;
- if (onmessage.isFunction()) {
+ if (script->callback.isFunction()) {
QScriptValue args = workerEngine->newArray(1);
- args.setProperty(0, variantToScriptValue(data->var, workerEngine));
+ args.setProperty(0, variantToScriptValue(data, workerEngine));
- onmessage.call(worker, args);
+ script->callback.call(script->object, args);
}
-
- if (data) delete data;
}
void QmlWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url)
@@ -190,14 +263,80 @@ void QmlWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url)
}
}
-WorkerDataEvent::WorkerDataEvent(int workerId, QmlWorkerScriptEngine::Data *data)
+QVariant QmlWorkerScriptEnginePrivate::scriptValueToVariant(const QScriptValue &value)
+{
+ if (value.isBool()) {
+ return QVariant(value.toBool());
+ } else if (value.isString()) {
+ return QVariant(value.toString());
+ } else if (value.isNumber()) {
+ return QVariant((qreal)value.toNumber());
+ } else if (value.isArray()) {
+ QVariantList list;
+
+ quint32 length = (quint32)value.property("length").toNumber();
+
+ for (quint32 ii = 0; ii < length; ++ii) {
+ QVariant v = scriptValueToVariant(ii);
+ list << v;
+ }
+
+ return QVariant(list);
+ } else if (value.isObject()) {
+ QVariantHash hash;
+
+ QScriptValueIterator iter(value);
+
+ while (iter.hasNext()) {
+ iter.next();
+ hash.insert(iter.name(), scriptValueToVariant(iter.value()));
+ }
+
+ return QVariant(hash);
+ }
+
+ return QVariant();
+
+}
+
+QScriptValue QmlWorkerScriptEnginePrivate::variantToScriptValue(const QVariant &value, QScriptEngine *engine)
+{
+ if (value.type() == QVariant::Bool) {
+ return QScriptValue(value.toBool());
+ } else if (value.type() == QVariant::String) {
+ return QScriptValue(value.toString());
+ } else if (value.type() == (QVariant::Type)QMetaType::QReal) {
+ return QScriptValue(value.toReal());
+ } else if (value.type() == (QVariant::Type)QMetaType::QVariantList) {
+ QVariantList list = qvariant_cast<QVariantList>(value);
+ QScriptValue rv = engine->newArray(list.count());
+
+ for (quint32 ii = 0; ii < list.count(); ++ii)
+ rv.setProperty(ii, variantToScriptValue(list.at(ii), engine));
+
+ return rv;
+ } else if (value.type() == (QVariant::Type)QMetaType::QVariantHash) {
+
+ QVariantHash hash = qvariant_cast<QVariantHash>(value);
+
+ QScriptValue rv = engine->newObject();
+
+ for (QVariantHash::ConstIterator iter = hash.begin(); iter != hash.end(); ++iter)
+ rv.setProperty(iter.key(), variantToScriptValue(iter.value(), engine));
+
+ return rv;
+ } else {
+ return engine->nullValue();
+ }
+}
+
+WorkerDataEvent::WorkerDataEvent(int workerId, const QVariant &data)
: QEvent((QEvent::Type)WorkerData), m_id(workerId), m_data(data)
{
}
WorkerDataEvent::~WorkerDataEvent()
{
- if (m_data) { delete m_data; m_data = 0; }
}
int WorkerDataEvent::workerId() const
@@ -205,11 +344,9 @@ int WorkerDataEvent::workerId() const
return m_id;
}
-QmlWorkerScriptEngine::Data *WorkerDataEvent::takeData()
+QVariant WorkerDataEvent::data() const
{
- QmlWorkerScriptEngine::Data *rv = m_data;
- m_data = 0;
- return rv;
+ return m_data;
}
WorkerLoadEvent::WorkerLoadEvent(int workerId, const QUrl &url)
@@ -227,6 +364,16 @@ QUrl WorkerLoadEvent::url() const
return m_url;
}
+WorkerRemoveEvent::WorkerRemoveEvent(int workerId)
+: QEvent((QEvent::Type)WorkerRemove), m_id(workerId)
+{
+}
+
+int WorkerRemoveEvent::workerId() const
+{
+ return m_id;
+}
+
QmlWorkerScriptEngine::QmlWorkerScriptEngine(QObject *parent)
: QThread(parent), d(new QmlWorkerScriptEnginePrivate)
{
@@ -234,6 +381,7 @@ QmlWorkerScriptEngine::QmlWorkerScriptEngine(QObject *parent)
start(QThread::LowPriority);
d->m_wait.wait(&d->m_lock);
d->moveToThread(this);
+ d->m_lock.unlock();
}
QmlWorkerScriptEngine::~QmlWorkerScriptEngine()
@@ -241,48 +389,44 @@ QmlWorkerScriptEngine::~QmlWorkerScriptEngine()
delete d; d = 0;
}
-QmlWorkerScriptEngine::WorkerScript::WorkerScript()
-: engine(0), id(0)
+QmlWorkerScriptEnginePrivate::WorkerScript::WorkerScript()
+: id(-1), initialized(false), owner(0)
{
}
-void QmlWorkerScriptEngine::WorkerScript::executeUrl(const QUrl &url)
+int QmlWorkerScriptEngine::registerWorkerScript(QmlWorkerScript *owner)
{
- engine->executeUrl(this, url);
-}
+ QmlWorkerScriptEnginePrivate::WorkerScript *script = new QmlWorkerScriptEnginePrivate::WorkerScript;
+ script->id = d->m_nextId++;
+ script->owner = owner;
-void QmlWorkerScriptEngine::WorkerScript::sendMessage(Data *data)
-{
- engine->sendMessage(this, data);
+ d->m_lock.lock();
+ d->workers.insert(script->id, script);
+ d->m_lock.unlock();
+
+ return script->id;
}
-void QmlWorkerScriptEngine::executeUrl(WorkerScript *script, const QUrl &data)
+void QmlWorkerScriptEngine::removeWorkerScript(int id)
{
- QCoreApplication::postEvent(d, new WorkerLoadEvent(script->id, data));
+ QCoreApplication::postEvent(d, new WorkerRemoveEvent(id));
}
-/*!
- Ownership of \a data transfers to QmlWorkerScriptEngine. It can not be modified by
- the caller.
-*/
-void QmlWorkerScriptEngine::sendMessage(WorkerScript *script, Data *data)
+void QmlWorkerScriptEngine::executeUrl(int id, const QUrl &url)
{
- QCoreApplication::postEvent(d, new WorkerDataEvent(script->id, data));
+ QCoreApplication::postEvent(d, new WorkerLoadEvent(id, url));
}
-QmlWorkerScriptEngine::WorkerScript *QmlWorkerScriptEngine::createWorkerScript()
+void QmlWorkerScriptEngine::sendMessage(int id, const QVariant &data)
{
- WorkerScript *rv = new WorkerScript;
- rv->engine = this;
- rv->id = d->m_nextId++;
- return rv;
+ QCoreApplication::postEvent(d, new WorkerDataEvent(id, data));
}
void QmlWorkerScriptEngine::run()
{
d->m_lock.lock();
- d->workerEngine = new QScriptEngine;
+ d->workerEngine = new QmlWorkerScriptEnginePrivate::ScriptEngine(d);
d->m_wait.wakeAll();
@@ -294,80 +438,13 @@ void QmlWorkerScriptEngine::run()
}
QmlWorkerScript::QmlWorkerScript(QObject *parent)
-: QObject(parent), m_script(0)
+: QObject(parent), m_engine(0), m_scriptId(-1)
{
}
QmlWorkerScript::~QmlWorkerScript()
{
- if (m_script) { delete m_script; m_script = 0; }
-}
-
-QVariant QmlWorkerScriptEnginePrivate::scriptValueToVariant(const QScriptValue &value)
-{
- if (value.isBool()) {
- return QVariant(value.toBool());
- } else if (value.isString()) {
- return QVariant(value.toString());
- } else if (value.isNumber()) {
- return QVariant((qreal)value.toNumber());
- } else if (value.isArray()) {
- QVariantList list;
-
- quint32 length = (quint32)value.property("length").toNumber();
-
- for (quint32 ii = 0; ii < length; ++ii) {
- QVariant v = scriptValueToVariant(ii);
- list << v;
- }
-
- return QVariant(list);
- } else if (value.isObject()) {
- QVariantHash hash;
-
- QScriptValueIterator iter(value);
-
- while (iter.hasNext()) {
- iter.next();
- hash.insert(iter.name(), scriptValueToVariant(iter.value()));
- }
-
- return QVariant(hash);
- }
-
- return QVariant();
-
-}
-
-QScriptValue QmlWorkerScriptEnginePrivate::variantToScriptValue(const QVariant &value, QScriptEngine *engine)
-{
- if (value.type() == QVariant::Bool) {
- return QScriptValue(value.toBool());
- } else if (value.type() == QVariant::String) {
- return QScriptValue(value.toString());
- } else if (value.type() == (QVariant::Type)QMetaType::QReal) {
- return QScriptValue(value.toReal());
- } else if (value.type() == (QVariant::Type)QMetaType::QVariantList) {
- QVariantList list = qvariant_cast<QVariantList>(value);
- QScriptValue rv = engine->newArray(list.count());
-
- for (quint32 ii = 0; ii < list.count(); ++ii)
- rv.setProperty(ii, variantToScriptValue(list.at(ii), engine));
-
- return rv;
- } else if (value.type() == (QVariant::Type)QMetaType::QVariantHash) {
-
- QVariantHash hash = qvariant_cast<QVariantHash>(value);
-
- QScriptValue rv = engine->newObject();
-
- for (QVariantHash::ConstIterator iter = hash.begin(); iter != hash.end(); ++iter)
- rv.setProperty(iter.key(), variantToScriptValue(iter.value(), engine));
-
- return rv;
- } else {
- return engine->nullValue();
- }
+ if (m_scriptId != -1) m_engine->removeWorkerScript(m_scriptId);
}
QUrl QmlWorkerScript::source() const
@@ -382,37 +459,55 @@ void QmlWorkerScript::setSource(const QUrl &source)
m_source = source;
- if (m_script)
- m_script->executeUrl(m_source);
+ if (m_engine)
+ m_engine->executeUrl(m_scriptId, m_source);
emit sourceChanged();
}
void QmlWorkerScript::sendMessage(const QScriptValue &message)
{
- if (!m_script) {
+ if (!m_engine) {
qWarning("QmlWorkerScript: Attempt to send message before WorkerScript establishment");
return;
}
- QmlWorkerScriptEngine::Data *data = new QmlWorkerScriptEngine::Data;
- data->var = QmlWorkerScriptEnginePrivate::scriptValueToVariant(message);
- m_script->sendMessage(data);
+ m_engine->sendMessage(m_scriptId, QmlWorkerScriptEnginePrivate::scriptValueToVariant(message));
}
void QmlWorkerScript::componentComplete()
{
- if (!m_script) {
+ if (!m_engine) {
QmlEngine *engine = qmlEngine(this);
if (!engine) {
qWarning("QmlWorkerScript: componentComplete() called without qmlEngine() set");
return;
}
- m_script = QmlEnginePrivate::get(engine)->getWorkerScriptEngine()->createWorkerScript();
+
+ m_engine = QmlEnginePrivate::get(engine)->getWorkerScriptEngine();
+ m_scriptId = m_engine->registerWorkerScript(this);
if (m_source.isValid())
- m_script->executeUrl(m_source);
+ m_engine->executeUrl(m_scriptId, m_source);
}
}
+bool QmlWorkerScript::event(QEvent *event)
+{
+ if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
+ QmlEngine *engine = qmlEngine(this);
+ if (engine) {
+ QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine);
+ WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
+ QScriptValue value =
+ QmlWorkerScriptEnginePrivate::variantToScriptValue(workerEvent->data(), scriptEngine);
+ emit message(value);
+ }
+ return true;
+ } else {
+ return QObject::event(event);
+ }
+}
+
+
QML_DEFINE_TYPE(Qt, 4, 6, WorkerScript, QmlWorkerScript);
diff --git a/src/declarative/qml/qmlworkerscript_p.h b/src/declarative/qml/qmlworkerscript_p.h
index b85238d..96394ae 100644
--- a/src/declarative/qml/qmlworkerscript_p.h
+++ b/src/declarative/qml/qmlworkerscript_p.h
@@ -59,6 +59,7 @@
#include <QtScript/qscriptvalue.h>
#include <QtCore/qurl.h>
+class QmlWorkerScript;
class QmlWorkerScriptEnginePrivate;
class QmlWorkerScriptEngine : public QThread
{
@@ -67,26 +68,10 @@ public:
QmlWorkerScriptEngine(QObject *parent = 0);
virtual ~QmlWorkerScriptEngine();
- class Data;
- class WorkerScript {
- public:
- void sendMessage(Data *);
- void executeUrl(const QUrl &);
-
- private:
- WorkerScript();
- friend class QmlWorkerScriptEngine;
- QmlWorkerScriptEngine *engine;
- int id;
- };
- WorkerScript *createWorkerScript();
-
- struct Data {
- QVariant var;
- };
-
- void executeUrl(WorkerScript *, const QUrl &);
- void sendMessage(WorkerScript *, Data *);
+ int registerWorkerScript(QmlWorkerScript *);
+ void removeWorkerScript(int);
+ void executeUrl(int, const QUrl &);
+ void sendMessage(int, const QVariant &);
protected:
virtual void run();
@@ -112,12 +97,15 @@ public slots:
signals:
void sourceChanged();
+ void message(const QScriptValue &messageObject);
protected:
virtual void componentComplete();
+ virtual bool event(QEvent *);
private:
- QmlWorkerScriptEngine::WorkerScript *m_script;
+ QmlWorkerScriptEngine *m_engine;
+ int m_scriptId;
QUrl m_source;
};
QML_DECLARE_TYPE(QmlWorkerScript);
diff --git a/tests/benchmarks/declarative/qmltime/example.qml b/tests/benchmarks/declarative/qmltime/example.qml
new file mode 100644
index 0000000..68889f0
--- /dev/null
+++ b/tests/benchmarks/declarative/qmltime/example.qml
@@ -0,0 +1,14 @@
+import Qt 4.6
+import QmlTime 1.0 as QmlTime
+
+Item {
+
+ property string name: "Bob Smith"
+
+ QmlTime.Timer {
+ component: Item {
+ Text { text: name }
+ }
+ }
+}
+
diff --git a/tests/benchmarks/declarative/qmltime/qmltime.cpp b/tests/benchmarks/declarative/qmltime/qmltime.cpp
new file mode 100644
index 0000000..27019f4
--- /dev/null
+++ b/tests/benchmarks/declarative/qmltime/qmltime.cpp
@@ -0,0 +1,133 @@
+#include <QmlEngine>
+#include <QmlComponent>
+#include <QDebug>
+#include <QApplication>
+#include <QTime>
+#include <QmlContext>
+
+class Timer : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QmlComponent *component READ component WRITE setComponent);
+
+public:
+ Timer();
+
+ QmlComponent *component() const;
+ void setComponent(QmlComponent *);
+
+ static Timer *timerInstance();
+
+ void run(uint);
+
+private:
+ QmlComponent *m_component;
+ static Timer *m_timer;
+};
+QML_DECLARE_TYPE(Timer);
+QML_DEFINE_TYPE(QmlTime, 1, 0, Timer, Timer);
+
+Timer *Timer::m_timer = 0;
+
+Timer::Timer()
+: m_component(0)
+{
+ if (m_timer)
+ qWarning("Timer: Timer already registered");
+ m_timer = this;
+}
+
+QmlComponent *Timer::component() const
+{
+ return m_component;
+}
+
+void Timer::setComponent(QmlComponent *c)
+{
+ m_component = c;
+}
+
+Timer *Timer::timerInstance()
+{
+ return m_timer;
+}
+
+void Timer::run(uint iterations)
+{
+ QmlContext context(qmlContext(this));
+
+ QTime t;
+ t.start();
+ for (uint ii = 0; ii < iterations; ++ii) {
+ QObject *o = m_component->create(&context);
+ delete o;
+ }
+
+ int e = t.elapsed();
+
+ qWarning() << "Total:" << e << "ms, Per iteration:" << qreal(e) / qreal(iterations) << "ms";
+
+}
+
+void usage(const char *name)
+{
+ qWarning("Usage: %s [-iterations <count>] <qml file>", name);
+ exit(-1);
+}
+
+int main(int argc, char ** argv)
+{
+ QApplication app(argc, argv);
+
+ uint iterations = 1024;
+ QString filename;
+
+ for (int ii = 1; ii < argc; ++ii) {
+ QByteArray arg(argv[ii]);
+
+ if (arg == "-iterations") {
+ if (ii + 1 < argc) {
+ ++ii;
+ QByteArray its(argv[ii]);
+ bool ok = false;
+ iterations = its.toUInt(&ok);
+ if (!ok)
+ usage(argv[0]);
+ } else {
+ usage(argv[0]);
+ }
+ } else {
+ filename = QLatin1String(argv[ii]);
+ }
+ }
+
+ QmlEngine engine;
+ QmlComponent component(&engine, filename);
+ if (component.isError()) {
+ qWarning() << component.errors();
+ return -1;
+ }
+
+ QObject *obj = component.create();
+ if (!obj) {
+ qWarning() << component.errors();
+ return -1;
+ }
+
+ Timer *timer = Timer::timerInstance();
+ if (!timer) {
+ qWarning() << "A Tester.Timer instance is required.";
+ return -1;
+ }
+
+ if (!timer->component()) {
+ qWarning() << "The timer has no component";
+ return -1;
+ }
+
+ timer->run(iterations);
+
+ return 0;
+}
+
+#include "qmltime.moc"
diff --git a/tests/benchmarks/declarative/qmltime/qmltime.pro b/tests/benchmarks/declarative/qmltime/qmltime.pro
new file mode 100644
index 0000000..b077d1a
--- /dev/null
+++ b/tests/benchmarks/declarative/qmltime/qmltime.pro
@@ -0,0 +1,8 @@
+load(qttest_p4)
+TEMPLATE = app
+TARGET = qmltime
+QT += declarative
+macx:CONFIG -= app_bundle
+
+SOURCES += qmltime.cpp
+