diff options
Diffstat (limited to 'src/qml/qml')
71 files changed, 1382 insertions, 2720 deletions
diff --git a/src/qml/qml/ftw/ftw.pri b/src/qml/qml/ftw/ftw.pri index 4b109107f9..51697b0aff 100644 --- a/src/qml/qml/ftw/ftw.pri +++ b/src/qml/qml/ftw/ftw.pri @@ -4,7 +4,6 @@ HEADERS += \ $$PWD/qpodvector_p.h \ $$PWD/qhashedstring_p.h \ $$PWD/qqmlrefcount_p.h \ - $$PWD/qqmlpool_p.h \ $$PWD/qfieldlist_p.h \ $$PWD/qhashfield_p.h \ $$PWD/qqmlthread_p.h \ @@ -20,7 +19,6 @@ HEADERS += \ SOURCES += \ $$PWD/qintrusivelist.cpp \ $$PWD/qhashedstring.cpp \ - $$PWD/qqmlpool.cpp \ $$PWD/qqmlthread.cpp \ # mirrors logic in $$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri diff --git a/src/qml/qml/ftw/qqmlpool.cpp b/src/qml/qml/ftw/qqmlpool.cpp deleted file mode 100644 index b86dcba107..0000000000 --- a/src/qml/qml/ftw/qqmlpool.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************** -** -** 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 "qqmlpool_p.h" -#include <stdlib.h> - -#ifdef Q_OS_QNX -#include <malloc.h> -#endif - -// #define POOL_DEBUG - -QT_BEGIN_NAMESPACE - -void QQmlPool::newpage() -{ -#ifdef POOL_DEBUG - qWarning("QQmlPool: Allocating page"); -#endif - - Page *page = (Page *)malloc(sizeof(Page)); - page->header.next = _page; - page->header.free = page->memory; - _page = page; -} - -void QQmlPool::clear() -{ -#ifdef POOL_DEBUG - int count = 0; -#endif - - Class *c = _classList; - while (c) { - Class *n = c->_next; - c->_destroy(c); -#ifdef POOL_DEBUG - ++count; -#endif - c = n; - } - -#ifdef POOL_DEBUG - qWarning("QQmlPool: Destroyed %d objects", count); -#endif - - Page *p = _page; - while (p) { - Page *n = p->header.next; - free(p); - p = n; - } - - _classList = 0; - _page = 0; -} - - -QT_END_NAMESPACE diff --git a/src/qml/qml/ftw/qqmlpool_p.h b/src/qml/qml/ftw/qqmlpool_p.h deleted file mode 100644 index 4956cd81d8..0000000000 --- a/src/qml/qml/ftw/qqmlpool_p.h +++ /dev/null @@ -1,270 +0,0 @@ -/**************************************************************************** -** -** 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 QQMLPOOL_P_H -#define QQMLPOOL_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qv4global_p.h> -#include <QtCore/qstring.h> -#include <QtCore/qurl.h> - -QT_BEGIN_NAMESPACE - -class Q_QML_PRIVATE_EXPORT QQmlPool -{ -public: - // The class has a destructor that needs to be called - class Class { - public: - inline QQmlPool *pool() const; - - private: - void *operator new(size_t); - void *operator new(size_t, void *m) { return m; } - friend class QQmlPool; - - QQmlPool *_pool; - Class *_next; - void (*_destroy)(Class *); - }; - - // The class is plain old data and no destructor needs to - // be called - class POD { - public: - inline QQmlPool *pool() const; - - private: - void *operator new(size_t); - void *operator new(size_t, void *m) { return m; } - friend class QQmlPool; - - QQmlPool *_pool; - }; - - inline QQmlPool(); - inline ~QQmlPool(); - - void clear(); - - template<typename T> - inline T *New(); - template<typename T> - inline T *NewRaw(); - template<typename T> - inline T *NewRawArray(int length); - - inline QString *NewString(const QString &); - inline QByteArray *NewByteArray(const QByteArray &); - inline QUrl *NewUrl(const QUrl &); - - template<typename T> - struct List { - List() : m_length(0), m_data(0) {} - List(const List &o) : m_length(o.m_length), m_data(o.m_data) {} - List &operator=(const List &o) { - m_length = o.m_length; - m_data = o.m_data; - return *this; - } - - int count() const { - return m_length; - } - int length() const { - return m_length; - } - const T &at(int index) const { - Q_ASSERT(index < m_length); - return m_data[index]; - }; - T &operator[](int index) { - Q_ASSERT(index < m_length); - return m_data[index]; - }; - const T *data() const { return m_data; } - private: - friend class QQmlPool; - List(T *d, int l) : m_length(l), m_data(d) {} - int m_length; - T *m_data; - }; - - template<typename T> - inline List<T> NewRawList(int length); - -private: - struct StringClass : public QString, public Class { - }; - struct ByteArrayClass : public QByteArray, public Class { - }; - struct UrlClass : public QUrl, public Class { - }; - - inline void *allocate(int size); - void newpage(); - - template<typename T> - inline void initialize(POD *); - template<typename T> - inline void initialize(Class *); - template<typename T> - static void destroy(Class *c); - - struct Page { - struct Header { - Page *next; - char *free; - } header; - - static const int pageSize = 4 * 4096 - sizeof(Header); - - char memory[pageSize]; - }; - - Page *_page; - Class *_classList; -}; - -QQmlPool::QQmlPool() -: _page(0), _classList(0) -{ -} - -QQmlPool::~QQmlPool() -{ - clear(); -} - -template<typename T> -T *QQmlPool::New() -{ - T *rv = new (allocate(sizeof(T))) T; - initialize<T>(rv); - rv->_pool = this; - return rv; -} - -template<typename T> -T *QQmlPool::NewRaw() -{ - return (T*)allocate(sizeof(T)); -} - -template<typename T> -T *QQmlPool::NewRawArray(int length) -{ - return (T*)allocate(length * sizeof(T)); -} - -template<typename T> -QQmlPool::List<T> QQmlPool::NewRawList(int length) -{ - return List<T>(NewRawArray<T>(length), length); -} - -QString *QQmlPool::NewString(const QString &s) -{ - QString *rv = New<StringClass>(); - *rv = s; - return rv; -} - -QByteArray *QQmlPool::NewByteArray(const QByteArray &s) -{ - QByteArray *rv = New<ByteArrayClass>(); - *rv = s; - return rv; -} - -QUrl *QQmlPool::NewUrl(const QUrl &s) -{ - QUrl *rv = New<UrlClass>(); - *rv = s; - return rv; -} - -void *QQmlPool::allocate(int size) -{ - if (!_page || (_page->header.free + size) > (_page->memory + Page::pageSize)) - newpage(); - - void *rv = _page->header.free; - _page->header.free += size + ((8 - size) & 7); // ensure 8 byte alignment; - return rv; -} - -template<typename T> -void QQmlPool::initialize(QQmlPool::POD *) -{ -} - -template<typename T> -void QQmlPool::initialize(QQmlPool::Class *c) -{ - c->_next = _classList; - c->_destroy = &destroy<T>; - _classList = c; -} - -template<typename T> -void QQmlPool::destroy(Class *c) -{ - static_cast<T *>(c)->~T(); -} - -QQmlPool *QQmlPool::Class::pool() const -{ - return _pool; -} - -QQmlPool *QQmlPool::POD::pool() const -{ - return _pool; -} - -QT_END_NAMESPACE - -#endif // QQMLPOOL_P_H - diff --git a/src/qml/qml/ftw/qqmlrefcount_p.h b/src/qml/qml/ftw/qqmlrefcount_p.h index 59ed77b580..ba2ca43990 100644 --- a/src/qml/qml/ftw/qqmlrefcount_p.h +++ b/src/qml/qml/ftw/qqmlrefcount_p.h @@ -72,13 +72,16 @@ template<class T> class QQmlRefPointer { public: + enum Mode { + AddRef, + Adopt + }; inline QQmlRefPointer(); - inline QQmlRefPointer(T *); + inline QQmlRefPointer(T *, Mode m = AddRef); inline QQmlRefPointer(const QQmlRefPointer<T> &); inline ~QQmlRefPointer(); inline QQmlRefPointer<T> &operator=(const QQmlRefPointer<T> &o); - inline QQmlRefPointer<T> &operator=(T *); inline bool isNull() const { return !o; } @@ -87,7 +90,7 @@ public: inline operator T*() const { return o; } inline T* data() const { return o; } - inline QQmlRefPointer<T> &take(T *); + inline QQmlRefPointer<T> &adopt(T *); private: T *o; @@ -133,10 +136,11 @@ QQmlRefPointer<T>::QQmlRefPointer() } template<class T> -QQmlRefPointer<T>::QQmlRefPointer(T *o) +QQmlRefPointer<T>::QQmlRefPointer(T *o, Mode m) : o(o) { - if (o) o->addref(); + if (m == AddRef && o) + o->addref(); } template<class T> @@ -161,21 +165,12 @@ QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(const QQmlRefPointer<T> &other) return *this; } -template<class T> -QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(T *other) -{ - if (other) other->addref(); - if (o) o->release(); - o = other; - return *this; -} - /*! Takes ownership of \a other. take() does *not* add a reference, as it assumes ownership of the callers reference of other. */ template<class T> -QQmlRefPointer<T> &QQmlRefPointer<T>::take(T *other) +QQmlRefPointer<T> &QQmlRefPointer<T>::adopt(T *other) { if (o) o->release(); o = other; diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp index 4addcd9e58..62f6f76a7e 100644 --- a/src/qml/qml/ftw/qqmlthread.cpp +++ b/src/qml/qml/ftw/qqmlthread.cpp @@ -377,4 +377,31 @@ void QQmlThread::internalPostMethodToMain(Message *message) d->unlock(); } +void QQmlThread::waitForNextMessage() +{ + Q_ASSERT(!isThisThread()); + d->lock(); + Q_ASSERT(d->m_mainThreadWaiting == false); + + d->m_mainThreadWaiting = true; + + if (d->mainSync || !d->threadList.isEmpty()) { + if (d->mainSync) { + QQmlThread::Message *message = d->mainSync; + unlock(); + message->call(this); + delete message; + lock(); + d->mainSync = 0; + wakeOne(); + } else { + d->wait(); + } + } + + d->m_mainThreadWaiting = false; + d->unlock(); +} + + QT_END_NAMESPACE diff --git a/src/qml/qml/ftw/qqmlthread_p.h b/src/qml/qml/ftw/qqmlthread_p.h index 86d7d2cf19..73658536ac 100644 --- a/src/qml/qml/ftw/qqmlthread_p.h +++ b/src/qml/qml/ftw/qqmlthread_p.h @@ -108,6 +108,8 @@ public: template<typename T, typename T2, class V, class V2, class O> inline void postMethodToMain(void (O::*Member)(V, V2), const T &, const T2 &); + void waitForNextMessage(); + protected: virtual void startupThread(); virtual void shutdownThread(); diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri index e733bcec05..4d84cc82ae 100644 --- a/src/qml/qml/qml.pri +++ b/src/qml/qml/qml.pri @@ -23,7 +23,6 @@ SOURCES += \ $$PWD/qqmlvaluetype.cpp \ $$PWD/qqmlaccessors.cpp \ $$PWD/qqmlxmlhttprequest.cpp \ - $$PWD/qqmlwatcher.cpp \ $$PWD/qqmlcleanup.cpp \ $$PWD/qqmlpropertycache.cpp \ $$PWD/qqmlnotifier.cpp \ @@ -35,7 +34,6 @@ SOURCES += \ $$PWD/qqmlimport.cpp \ $$PWD/qqmllist.cpp \ $$PWD/qqmllocale.cpp \ - $$PWD/qqmlabstractexpression.cpp \ $$PWD/qqmljavascriptexpression.cpp \ $$PWD/qqmlabstractbinding.cpp \ $$PWD/qqmlvaluetypeproxybinding.cpp \ @@ -92,7 +90,6 @@ HEADERS += \ $$PWD/qqmlvaluetype_p.h \ $$PWD/qqmlaccessors_p.h \ $$PWD/qqmlxmlhttprequest_p.h \ - $$PWD/qqmlwatcher_p.h \ $$PWD/qqmlcleanup_p.h \ $$PWD/qqmlpropertycache_p.h \ $$PWD/qqmlnotifier_p.h \ @@ -107,7 +104,6 @@ HEADERS += \ $$PWD/qqmlscriptstring_p.h \ $$PWD/qqmllocale_p.h \ $$PWD/qqmlcomponentattached_p.h \ - $$PWD/qqmlabstractexpression_p.h \ $$PWD/qqmljavascriptexpression_p.h \ $$PWD/qqmlabstractbinding_p.h \ $$PWD/qqmlvaluetypeproxybinding_p.h \ diff --git a/src/qml/qml/qqmlabstractbinding.cpp b/src/qml/qml/qqmlabstractbinding.cpp index 40c8f451b4..4e0763e95a 100644 --- a/src/qml/qml/qqmlabstractbinding.cpp +++ b/src/qml/qml/qqmlabstractbinding.cpp @@ -39,24 +39,19 @@ QT_BEGIN_NAMESPACE -extern QQmlAbstractBinding::VTable QQmlBinding_vtable; -extern QQmlAbstractBinding::VTable QQmlValueTypeProxyBinding_vtable; - -QQmlAbstractBinding::VTable *QQmlAbstractBinding::vTables[] = { - &QQmlBinding_vtable, - &QQmlValueTypeProxyBinding_vtable -}; - -QQmlAbstractBinding::QQmlAbstractBinding(BindingType bt) - : m_nextBindingPtr(bt) +QQmlAbstractBinding::QQmlAbstractBinding() + : m_targetIndex(-1) { + Q_ASSERT(!isAddedToObject()); } QQmlAbstractBinding::~QQmlAbstractBinding() { - Q_ASSERT(isAddedToObject() == false); - Q_ASSERT(nextBinding() == 0); - Q_ASSERT(*m_mePtr == 0); + Q_ASSERT(!ref); + Q_ASSERT(!isAddedToObject()); + + if (m_nextBinding.data() && !m_nextBinding->ref.deref()) + delete m_nextBinding.data(); } /*! @@ -72,40 +67,45 @@ void QQmlAbstractBinding::addToObject() Q_ASSERT(!nextBinding()); Q_ASSERT(isAddedToObject() == false); - QObject *obj = object(); + QObject *obj = targetObject(); Q_ASSERT(obj); QQmlData *data = QQmlData::get(obj, true); int coreIndex; - if (QQmlPropertyData::decodeValueTypePropertyIndex(propertyIndex(), &coreIndex) != -1) { + if (QQmlPropertyData::decodeValueTypePropertyIndex(targetPropertyIndex(), &coreIndex) != -1) { // Value type // Find the value type proxy (if there is one) QQmlValueTypeProxyBinding *proxy = 0; if (data->hasBindingBit(coreIndex)) { QQmlAbstractBinding *b = data->bindings; - while (b && b->propertyIndex() != coreIndex) + while (b && b->targetPropertyIndex() != coreIndex) b = b->nextBinding(); - Q_ASSERT(b && b->bindingType() == QQmlAbstractBinding::ValueTypeProxy); + Q_ASSERT(b && b->isValueTypeProxy()); proxy = static_cast<QQmlValueTypeProxyBinding *>(b); } if (!proxy) { proxy = new QQmlValueTypeProxyBinding(obj, coreIndex); - Q_ASSERT(proxy->propertyIndex() == coreIndex); - Q_ASSERT(proxy->object() == obj); + Q_ASSERT(proxy->targetPropertyIndex() == coreIndex); + Q_ASSERT(proxy->targetObject() == obj); proxy->addToObject(); } - setNextBinding(proxy->m_bindings); + setNextBinding(proxy->m_bindings.data()); proxy->m_bindings = this; } else { setNextBinding(data->bindings); + if (data->bindings) { + data->bindings->ref.deref(); + Q_ASSERT(data->bindings->ref.refCount > 0); + } data->bindings = this; + ref.ref(); data->setBindingBit(obj, coreIndex); } @@ -118,95 +118,81 @@ Remove the binding from the object. */ void QQmlAbstractBinding::removeFromObject() { - if (isAddedToObject()) { - QObject *obj = object(); - QQmlData *data = QQmlData::get(obj, false); - Q_ASSERT(data); - - int coreIndex; - if (QQmlPropertyData::decodeValueTypePropertyIndex(propertyIndex(), &coreIndex) != -1) { - - // Find the value type binding - QQmlAbstractBinding *vtbinding = data->bindings; - while (vtbinding->propertyIndex() != coreIndex) { - vtbinding = vtbinding->nextBinding(); - Q_ASSERT(vtbinding); - } - Q_ASSERT(vtbinding->bindingType() == QQmlAbstractBinding::ValueTypeProxy); - - QQmlValueTypeProxyBinding *vtproxybinding = - static_cast<QQmlValueTypeProxyBinding *>(vtbinding); - - QQmlAbstractBinding *binding = vtproxybinding->m_bindings; - if (binding == this) { - vtproxybinding->m_bindings = nextBinding(); - } else { - while (binding->nextBinding() != this) { - binding = binding->nextBinding(); - Q_ASSERT(binding); - } - binding->setNextBinding(nextBinding()); - } - - // Value type - we don't remove the proxy from the object. It will sit their happily - // doing nothing until it is removed by a write, a binding change or it is reused - // to hold more sub-bindings. + if (!isAddedToObject()) + return; - } else { + setAddedToObject(false); - if (data->bindings == this) { - data->bindings = nextBinding(); - } else { - QQmlAbstractBinding *binding = data->bindings; - while (binding->nextBinding() != this) { - binding = binding->nextBinding(); - Q_ASSERT(binding); - } - binding->setNextBinding(nextBinding()); - } - - data->clearBindingBit(coreIndex); - } + QObject *obj = targetObject(); + QQmlData *data = QQmlData::get(obj, false); + Q_ASSERT(data); - setNextBinding(0); - setAddedToObject(false); - } -} + QQmlAbstractBinding::Ptr next; + next = nextBinding(); + setNextBinding(0); -void QQmlAbstractBinding::printBindingLoopError(QQmlProperty &prop) -{ - qmlInfo(prop.object()) << QString(QLatin1String("Binding loop detected for property \"%1\"")).arg(prop.name()); -} + int coreIndex; + if (QQmlPropertyData::decodeValueTypePropertyIndex(targetPropertyIndex(), &coreIndex) != -1) { + // Find the value type binding + QQmlAbstractBinding *vtbinding = data->bindings; + while (vtbinding->targetPropertyIndex() != coreIndex) { + vtbinding = vtbinding->nextBinding(); + Q_ASSERT(vtbinding); + } + Q_ASSERT(vtbinding->isValueTypeProxy()); -static void bindingDummyDeleter(QQmlAbstractBinding *) -{ -} + QQmlValueTypeProxyBinding *vtproxybinding = + static_cast<QQmlValueTypeProxyBinding *>(vtbinding); -QQmlAbstractBinding::Pointer QQmlAbstractBinding::weakPointer() -{ - if (m_mePtr.value().isNull()) - m_mePtr.value() = QSharedPointer<QQmlAbstractBinding>(this, bindingDummyDeleter); + QQmlAbstractBinding *binding = vtproxybinding->m_bindings.data(); + if (binding == this) { + vtproxybinding->m_bindings = next; + } else { + while (binding->nextBinding() != this) { + binding = binding->nextBinding(); + Q_ASSERT(binding); + } + binding->setNextBinding(next.data()); + } - return m_mePtr.value().toWeakRef(); -} + // Value type - we don't remove the proxy from the object. It will sit their happily + // doing nothing until it is removed by a write, a binding change or it is reused + // to hold more sub-bindings. + return; + } -void QQmlAbstractBinding::clear() -{ - if (!m_mePtr.isNull()) { - **m_mePtr = 0; - m_mePtr = 0; + if (data->bindings == this) { + if (next.data()) + next->ref.ref(); + data->bindings = next.data(); + if (!ref.deref()) + delete this; + } else { + QQmlAbstractBinding *binding = data->bindings; + while (binding->nextBinding() != this) { + binding = binding->nextBinding(); + Q_ASSERT(binding); + } + binding->setNextBinding(next.data()); } + + data->clearBindingBit(coreIndex); } -void QQmlAbstractBinding::default_retargetBinding(QQmlAbstractBinding *, QObject *, int) +void QQmlAbstractBinding::printBindingLoopError(QQmlProperty &prop) { - qFatal("QQmlAbstractBinding::retargetBinding() called on illegal binding."); + qmlInfo(prop.object()) << QString(QLatin1String("Binding loop detected for property \"%1\"")).arg(prop.name()); } -QString QQmlAbstractBinding::default_expression(const QQmlAbstractBinding *) +QString QQmlAbstractBinding::expression() const { return QLatin1String("<Unknown>"); } +bool QQmlAbstractBinding::isValueTypeProxy() const +{ + return false; +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlabstractbinding_p.h b/src/qml/qml/qqmlabstractbinding_p.h index b5d8181ca5..dd14301aa9 100644 --- a/src/qml/qml/qqmlabstractbinding_p.h +++ b/src/qml/qml/qqmlabstractbinding_p.h @@ -46,6 +46,7 @@ // #include <QtCore/qsharedpointer.h> +#include <QtCore/qshareddata.h> #include <private/qtqmlglobal_p.h> #include <private/qqmlproperty_p.h> #include <private/qpointervaluepair_p.h> @@ -56,162 +57,83 @@ class QQmlObjectCreator; class Q_QML_PRIVATE_EXPORT QQmlAbstractBinding { +protected: + QQmlAbstractBinding(); public: - enum DestroyMode { - - // The binding should disconnect itself upon destroy - DisconnectBinding, - - // The binding doesn't need to disconnect itself, but it can if it wants to. - // - // This is used in QQmlData::destroyed() - at the point at which the bindings are - // destroyed, the notifiers are already disconnected, so no need to disconnect each - // binding again. - // - // Bindings can use this flag to speed up destruction, especially for v4 bindings - // disconnecting a single binding might be slow. - KeepBindingConnected - }; - - struct VTable { - void (*destroy)(QQmlAbstractBinding *, DestroyMode destroyMode); - QString (*expression)(const QQmlAbstractBinding *); - int (*propertyIndex)(const QQmlAbstractBinding *); - QObject *(*object)(const QQmlAbstractBinding *); - void (*setEnabled)(QQmlAbstractBinding *, bool, QQmlPropertyPrivate::WriteFlags); - void (*update)(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags); - void (*retargetBinding)(QQmlAbstractBinding *, QObject *, int); - }; - - typedef QWeakPointer<QQmlAbstractBinding> Pointer; + virtual ~QQmlAbstractBinding(); - enum BindingType { Binding = 0, ValueTypeProxy = 1 }; - inline BindingType bindingType() const; + typedef QExplicitlySharedDataPointer<QQmlAbstractBinding> Ptr; - // Destroy the binding. Use this instead of calling delete. - // Bindings are free to implement their own memory management, so the delete operator is - // not necessarily safe. The default implementation clears the binding, removes it from - // the object and calls delete. - void destroy(DestroyMode destroyMode = DisconnectBinding) - { vtable()->destroy(this, destroyMode); } + virtual QString expression() const; - QString expression() const { return vtable()->expression(this); } + virtual bool isValueTypeProxy() const; // Should return the encoded property index for the binding. Should return this value // even if the binding is not enabled or added to an object. // Encoding is: coreIndex | (valueTypeIndex << 16) - int propertyIndex() const { return vtable()->propertyIndex(this); } + int targetPropertyIndex() const { return m_targetIndex; } // Should return the object for the binding. Should return this object even if the // binding is not enabled or added to the object. - QObject *object() const { return vtable()->object(this); } - - void setEnabled(bool e) { setEnabled(e, QQmlPropertyPrivate::DontRemoveBinding); } - void setEnabled(bool e, QQmlPropertyPrivate::WriteFlags f) { vtable()->setEnabled(this, e, f); } + QObject *targetObject() const { return m_target.data(); } - void update() { update(QQmlPropertyPrivate::DontRemoveBinding); } - void update(QQmlPropertyPrivate::WriteFlags f) { vtable()->update(this, f); } + virtual void setEnabled(bool e, QQmlPropertyPrivate::WriteFlags f = QQmlPropertyPrivate::DontRemoveBinding) = 0; void addToObject(); void removeFromObject(); - static inline Pointer getPointer(QQmlAbstractBinding *p); static void printBindingLoopError(QQmlProperty &prop); - // Default implementation for some VTable functions - template<typename T> - static void default_destroy(QQmlAbstractBinding *, DestroyMode); - static QString default_expression(const QQmlAbstractBinding *); - static void default_retargetBinding(QQmlAbstractBinding *, QObject *, int); - -protected: - QQmlAbstractBinding(BindingType); - ~QQmlAbstractBinding(); - void clear(); + inline QQmlAbstractBinding *nextBinding() const; - // Called by QQmlPropertyPrivate to "move" a binding to a different property. - // This is only used for alias properties. The default implementation qFatal()'s - // to ensure that the method is never called for binding types that don't support it. - void retargetBinding(QObject *o, int i) { vtable()->retargetBinding(this, o, i); } -private: - Pointer weakPointer(); + struct RefCount { + RefCount() : refCount(0) {} + int refCount; + void ref() { ++refCount; } + int deref() { return --refCount; } + operator int() const { return refCount; } + }; + RefCount ref; +protected: friend class QQmlData; - friend class QQmlComponentPrivate; friend class QQmlValueTypeProxyBinding; - friend class QQmlPropertyPrivate; - friend class QtSharedPointer::ExternalRefCount<QQmlAbstractBinding>; - friend class QV4Bindings; friend class QQmlObjectCreator; - typedef QSharedPointer<QQmlAbstractBinding> SharedPointer; - // To save memory, we also store the rarely used weakPointer() instance in here - // We also use the flag bits: - // m_mePtr.flag1: added to object - QPointerValuePair<QQmlAbstractBinding*, SharedPointer> m_mePtr; - inline void setAddedToObject(bool v); inline bool isAddedToObject() const; - inline QQmlAbstractBinding *nextBinding() const; inline void setNextBinding(QQmlAbstractBinding *); + int m_targetIndex; + QFlagPointer<QObject> m_target; // Pointer to the next binding in the linked list of bindings. - // Being a pointer, the address is always aligned to at least 4 bytes, which means the last two - // bits of the pointer are free to be used for something else. They are used to store the binding - // type. The binding type serves as an index into the static vTables array, which is used instead - // of a compiler-generated vTable. Instead of virtual functions, pointers to static functions in - // the vTables array are used for dispatching. - // This saves a compiler-generated pointer to a compiler-generated vTable, and thus reduces - // the binding object size by sizeof(void*). - qintptr m_nextBindingPtr; - - static VTable *vTables[]; - inline const VTable *vtable() const { return vTables[bindingType()]; } + QFlagPointer<QQmlAbstractBinding> m_nextBinding; }; -QQmlAbstractBinding::Pointer -QQmlAbstractBinding::getPointer(QQmlAbstractBinding *p) -{ - return p ? p->weakPointer() : Pointer(); -} - void QQmlAbstractBinding::setAddedToObject(bool v) { - m_mePtr.setFlagValue(v); + m_nextBinding.setFlagValue(v); } bool QQmlAbstractBinding::isAddedToObject() const { - return m_mePtr.flag(); + return m_nextBinding.flag(); } QQmlAbstractBinding *QQmlAbstractBinding::nextBinding() const { - return (QQmlAbstractBinding *)(m_nextBindingPtr & ~0x3); + return m_nextBinding.data(); } void QQmlAbstractBinding::setNextBinding(QQmlAbstractBinding *b) { - m_nextBindingPtr = qintptr(b) | (m_nextBindingPtr & 0x3); -} - -QQmlAbstractBinding::BindingType QQmlAbstractBinding::bindingType() const -{ - return (BindingType)(m_nextBindingPtr & 0x3); -} - -template<typename T> -void QQmlAbstractBinding::default_destroy(QQmlAbstractBinding *This, DestroyMode mode) -{ - // Assume the binding disconnects itself in the destructor, which for example QQmlBinding - // does in the destructor of its base class, QQmlJavaScriptExpression - Q_UNUSED(mode); - - This->removeFromObject(); - This->clear(); - delete static_cast<T *>(This); + if (b) + b->ref.ref(); + if (m_nextBinding.data() && !m_nextBinding->ref.deref()) + delete m_nextBinding.data(); + m_nextBinding = b; } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlabstractexpression.cpp b/src/qml/qml/qqmlabstractexpression.cpp deleted file mode 100644 index c55c86952c..0000000000 --- a/src/qml/qml/qqmlabstractexpression.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/**************************************************************************** -** -** 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 "qqmlabstractexpression_p.h" - -QT_BEGIN_NAMESPACE - -QQmlAbstractExpression::QQmlAbstractExpression() -: m_prevExpression(0), m_nextExpression(0) -{ -} - -QQmlAbstractExpression::~QQmlAbstractExpression() -{ - if (m_prevExpression) { - *m_prevExpression = m_nextExpression; - if (m_nextExpression) - m_nextExpression->m_prevExpression = m_prevExpression; - } - - if (m_context.isT2()) - m_context.asT2()->_s = 0; -} - -QQmlContextData *QQmlAbstractExpression::context() const -{ - if (m_context.isT1()) return m_context.asT1(); - else return m_context.asT2()->_c; -} - -void QQmlAbstractExpression::setContext(QQmlContextData *context) -{ - if (m_prevExpression) { - *m_prevExpression = m_nextExpression; - if (m_nextExpression) - m_nextExpression->m_prevExpression = m_prevExpression; - m_prevExpression = 0; - m_nextExpression = 0; - } - - if (m_context.isT1()) m_context = context; - else m_context.asT2()->_c = context; - - if (context) { - m_nextExpression = context->expressions; - if (m_nextExpression) - m_nextExpression->m_prevExpression = &m_nextExpression; - m_prevExpression = &context->expressions; - context->expressions = this; - } -} - -void QQmlAbstractExpression::refresh() -{ -} - -bool QQmlAbstractExpression::isValid() const -{ - return context() != 0; -} - -QT_END_NAMESPACE - diff --git a/src/qml/qml/qqmlabstractexpression_p.h b/src/qml/qml/qqmlabstractexpression_p.h deleted file mode 100644 index 82ba010434..0000000000 --- a/src/qml/qml/qqmlabstractexpression_p.h +++ /dev/null @@ -1,116 +0,0 @@ -/**************************************************************************** -** -** 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 QQMLABSTRACTEXPRESSION_P_H -#define QQMLABSTRACTEXPRESSION_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qqmlcontext_p.h> -#include <private/qfieldlist_p.h> -#include <private/qflagpointer_p.h> - -QT_BEGIN_NAMESPACE - -class Q_QML_PRIVATE_EXPORT QQmlAbstractExpression -{ -public: - QQmlAbstractExpression(); - virtual ~QQmlAbstractExpression(); - - bool isValid() const; - - QQmlContextData *context() const; - void setContext(QQmlContextData *); - - virtual void refresh(); - - class DeleteWatcher { - public: - inline DeleteWatcher(QQmlAbstractExpression *); - inline ~DeleteWatcher(); - inline bool wasDeleted() const; - private: - friend class QQmlAbstractExpression; - QQmlContextData *_c; - QQmlAbstractExpression **_w; - QQmlAbstractExpression *_s; - }; - -private: - friend class QQmlContext; - friend class QQmlContextData; - friend class QQmlContextPrivate; - - QBiPointer<QQmlContextData, DeleteWatcher> m_context; - QQmlAbstractExpression **m_prevExpression; - QQmlAbstractExpression *m_nextExpression; -}; - -QQmlAbstractExpression::DeleteWatcher::DeleteWatcher(QQmlAbstractExpression *e) -: _c(0), _w(0), _s(e) -{ - if (e->m_context.isT1()) { - _w = &_s; - _c = e->m_context.asT1(); - e->m_context = this; - } else { - // Another watcher is already registered - _w = &e->m_context.asT2()->_s; - } -} - -QQmlAbstractExpression::DeleteWatcher::~DeleteWatcher() -{ - Q_ASSERT(*_w == 0 || (*_w == _s && _s->m_context.isT2())); - if (*_w && _s->m_context.asT2() == this) - _s->m_context = _c; -} - -bool QQmlAbstractExpression::DeleteWatcher::wasDeleted() const -{ - return *_w == 0; -} - -QT_END_NAMESPACE - -#endif // QQMLABSTRACTEXPRESSION_P_H diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index f223d099e4..3613c17242 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -43,43 +43,28 @@ #include <private/qqmlscriptstring_p.h> #include <private/qqmlcontextwrapper_p.h> #include <private/qqmlbuiltinfunctions_p.h> +#include <private/qqmlvmemetaobject_p.h> +#include <private/qqmlvaluetypewrapper_p.h> #include <QVariant> #include <QtCore/qdebug.h> QT_BEGIN_NAMESPACE -// Used in qqmlabstractbinding.cpp -QQmlAbstractBinding::VTable QQmlBinding_vtable = { - QQmlAbstractBinding::default_destroy<QQmlBinding>, - QQmlBinding::expression, - QQmlBinding::propertyIndex, - QQmlBinding::object, - QQmlBinding::setEnabled, - QQmlBinding::update, - QQmlBinding::retargetBinding -}; - -QQmlBinding::Identifier QQmlBinding::Invalid = -1; - -static QQmlJavaScriptExpression::VTable QQmlBinding_jsvtable = { - QQmlBinding::expressionIdentifier, - QQmlBinding::expressionChanged -}; - QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContext *ctxt) -: QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding) + : QQmlJavaScriptExpression(), + QQmlAbstractBinding() { setNotifyOnValueChanged(true); - QQmlAbstractExpression::setContext(QQmlContextData::get(ctxt)); + QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt)); setScopeObject(obj); - QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(context()->engine)->v4engine(); - v4function.set(v4, qmlBinding(context(), obj, str, QString(), 0)); + createQmlBinding(context(), obj, str, QString(), 0); } QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlContext *ctxt) -: QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding) + : QQmlJavaScriptExpression(), + QQmlAbstractBinding() { if (ctxt && !ctxt->isValid()) return; @@ -100,51 +85,52 @@ QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlConte } setNotifyOnValueChanged(true); - QQmlAbstractExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context)); + QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context)); setScopeObject(obj ? obj : scriptPrivate->scope); QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(context()->engine)->v4engine(); if (runtimeFunction) { - v4function.set(v4, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxtdata, scopeObject(), runtimeFunction)); + m_function.set(v4, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxtdata, scopeObject(), runtimeFunction)); } else { QString code = scriptPrivate->script; - v4function.set(v4, qmlBinding(context(), scopeObject(), code, url, scriptPrivate->lineNumber)); + createQmlBinding(context(), scopeObject(), code, url, scriptPrivate->lineNumber); } } QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContextData *ctxt) -: QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding) + : QQmlJavaScriptExpression(), + QQmlAbstractBinding() { setNotifyOnValueChanged(true); - QQmlAbstractExpression::setContext(ctxt); + QQmlJavaScriptExpression::setContext(ctxt); setScopeObject(obj); - QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(context()->engine)->v4engine(); - v4function.set(v4, qmlBinding(ctxt, obj, str, QString(), 0)); + createQmlBinding(ctxt, obj, str, QString(), 0); } QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContextData *ctxt, const QString &url, quint16 lineNumber, quint16 columnNumber) -: QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding) + : QQmlJavaScriptExpression(), + QQmlAbstractBinding() { Q_UNUSED(columnNumber); setNotifyOnValueChanged(true); - QQmlAbstractExpression::setContext(ctxt); + QQmlJavaScriptExpression::setContext(ctxt); setScopeObject(obj); - QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(context()->engine)->v4engine(); - v4function.set(v4, qmlBinding(ctxt, obj, str, url, lineNumber)); + createQmlBinding(ctxt, obj, str, url, lineNumber); } QQmlBinding::QQmlBinding(const QV4::Value &functionPtr, QObject *obj, QQmlContextData *ctxt) -: QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding) + : QQmlJavaScriptExpression(), + QQmlAbstractBinding() { setNotifyOnValueChanged(true); - QQmlAbstractExpression::setContext(ctxt); + QQmlJavaScriptExpression::setContext(ctxt); setScopeObject(obj); - v4function.set(functionPtr.asObject()->engine(), functionPtr); + m_function.set(functionPtr.as<QV4::Object>()->engine(), functionPtr); } QQmlBinding::~QQmlBinding() @@ -162,90 +148,243 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags) return; // Check that the target has not been deleted - if (QQmlData::wasDeleted(object())) + if (QQmlData::wasDeleted(targetObject())) return; QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine); QV4::Scope scope(ep->v4engine()); - QV4::ScopedFunctionObject f(scope, v4function.value()); + QV4::ScopedFunctionObject f(scope, m_function.value()); Q_ASSERT(f); - if (!updatingFlag()) { - QQmlBindingProfiler prof(ep->profiler, f); - setUpdatingFlag(true); + if (updatingFlag()) { + QQmlProperty p = QQmlPropertyPrivate::restore(targetObject(), getPropertyData(), 0); + QQmlAbstractBinding::printBindingLoopError(p); + return; + } + + QQmlBindingProfiler prof(ep->profiler, f); + setUpdatingFlag(true); - QQmlAbstractExpression::DeleteWatcher watcher(this); + QQmlJavaScriptExpression::DeleteWatcher watcher(this); - if (m_core.propType == qMetaTypeId<QQmlBinding *>()) { + QQmlPropertyData pd = getPropertyData(); - int idx = m_core.coreIndex; - Q_ASSERT(idx != -1); + if (pd.propType == qMetaTypeId<QQmlBinding *>()) { - QQmlBinding *t = this; - int status = -1; - void *a[] = { &t, 0, &status, &flags }; - QMetaObject::metacall(*m_coreObject, QMetaObject::WriteProperty, idx, a); + int idx = pd.coreIndex; + Q_ASSERT(idx != -1); - } else { - ep->referenceScarceResources(); + QQmlBinding *t = this; + int status = -1; + void *a[] = { &t, 0, &status, &flags }; + QMetaObject::metacall(*m_target, QMetaObject::WriteProperty, idx, a); - bool isUndefined = false; + } else { + ep->referenceScarceResources(); - QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(context(), f, &isUndefined)); + bool isUndefined = false; - bool needsErrorLocationData = false; - if (!watcher.wasDeleted() && !hasError()) - needsErrorLocationData = !QQmlPropertyPrivate::writeBinding(*m_coreObject, m_core, context(), - this, result, isUndefined, flags); + QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined)); - if (!watcher.wasDeleted()) { + bool error = false; + if (!watcher.wasDeleted() && isAddedToObject() && !hasError()) + error = !write(pd, result, isUndefined, flags); - if (needsErrorLocationData) - delayedError()->setErrorLocation(f->sourceLocation()); + if (!watcher.wasDeleted()) { - if (hasError()) { - if (!delayedError()->addError(ep)) ep->warning(this->error(context()->engine)); - } else { - clearError(); - } + if (error) { + delayedError()->setErrorLocation(f->sourceLocation()); + delayedError()->setErrorObject(m_target.data()); + } + if (hasError()) { + if (!delayedError()->addError(ep)) ep->warning(this->error(context()->engine)); + } else { + clearError(); } - ep->dereferenceScarceResources(); } - if (!watcher.wasDeleted()) - setUpdatingFlag(false); - } else { - QQmlProperty p = property(); - QQmlAbstractBinding::printBindingLoopError(p); + ep->dereferenceScarceResources(); } + + if (!watcher.wasDeleted()) + setUpdatingFlag(false); +} + +// Returns true if successful, false if an error description was set on expression +bool QQmlBinding::write(const QQmlPropertyData &core, + const QV4::Value &result, bool isUndefined, + QQmlPropertyPrivate::WriteFlags flags) +{ + Q_ASSERT(m_target.data()); + Q_ASSERT(core.coreIndex != -1); + + QQmlEngine *engine = context()->engine; + QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine); + +#define QUICK_STORE(cpptype, conversion) \ + { \ + cpptype o = (conversion); \ + int status = -1; \ + void *argv[] = { &o, 0, &status, &flags }; \ + QMetaObject::metacall(m_target.data(), QMetaObject::WriteProperty, core.coreIndex, argv); \ + return true; \ + } \ + + + if (!isUndefined && !core.isValueTypeVirtual()) { + switch (core.propType) { + case QMetaType::Int: + if (result.isInteger()) + QUICK_STORE(int, result.integerValue()) + else if (result.isNumber()) + QUICK_STORE(int, result.doubleValue()) + break; + case QMetaType::Double: + if (result.isNumber()) + QUICK_STORE(double, result.asDouble()) + break; + case QMetaType::Float: + if (result.isNumber()) + QUICK_STORE(float, result.asDouble()) + break; + case QMetaType::QString: + if (result.isString()) + QUICK_STORE(QString, result.toQStringNoThrow()) + break; + default: + if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) { + if (vtw->d()->valueType->typeId == core.propType) { + return vtw->write(m_target.data(), core.coreIndex); + } + } + break; + } + } +#undef QUICK_STORE + + int type = core.isValueTypeVirtual() ? core.valueTypePropType : core.propType; + + QQmlJavaScriptExpression::DeleteWatcher watcher(this); + + QVariant value; + bool isVarProperty = core.isVarProperty(); + + if (isUndefined) { + } else if (core.isQList()) { + value = QV8Engine::getV4(v8engine)->toVariant(result, qMetaTypeId<QList<QObject *> >()); + } else if (result.isNull() && core.isQObject()) { + value = QVariant::fromValue((QObject *)0); + } else if (core.propType == qMetaTypeId<QList<QUrl> >()) { + value = QQmlPropertyPrivate::resolvedUrlSequence(QV8Engine::getV4(v8engine)->toVariant(result, qMetaTypeId<QList<QUrl> >()), context()); + } else if (!isVarProperty && type != qMetaTypeId<QJSValue>()) { + value = QV8Engine::getV4(v8engine)->toVariant(result, type); + } + + if (hasError()) { + return false; + } else if (isVarProperty) { + const QV4::FunctionObject *f = result.as<QV4::FunctionObject>(); + if (f && f->isBinding()) { + // we explicitly disallow this case to avoid confusion. Users can still store one + // in an array in a var property if they need to, but the common case is user error. + delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); + return false; + } + + QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_target.data()); + Q_ASSERT(vmemo); + vmemo->setVMEProperty(core.coreIndex, result); + } else if (isUndefined && core.isResettable()) { + void *args[] = { 0 }; + QMetaObject::metacall(m_target.data(), QMetaObject::ResetProperty, core.coreIndex, args); + } else if (isUndefined && type == qMetaTypeId<QVariant>()) { + QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, QVariant(), context(), flags); + } else if (type == qMetaTypeId<QJSValue>()) { + const QV4::FunctionObject *f = result.as<QV4::FunctionObject>(); + if (f && f->isBinding()) { + delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); + return false; + } + QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, QVariant::fromValue( + QJSValue(QV8Engine::getV4(v8engine), result.asReturnedValue())), + context(), flags); + } else if (isUndefined) { + QString errorStr = QLatin1String("Unable to assign [undefined] to "); + if (!QMetaType::typeName(type)) + errorStr += QLatin1String("[unknown property type]"); + else + errorStr += QLatin1String(QMetaType::typeName(type)); + delayedError()->setErrorDescription(errorStr); + return false; + } else if (const QV4::FunctionObject *f = result.as<QV4::FunctionObject>()) { + if (f->isBinding()) + delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); + else + delayedError()->setErrorDescription(QLatin1String("Unable to assign a function to a property of any type other than var.")); + return false; + } else if (!QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, value, context(), flags)) { + + if (watcher.wasDeleted()) + return true; + + const char *valueType = 0; + const char *propertyType = 0; + + if (value.userType() == QMetaType::QObjectStar) { + if (QObject *o = *(QObject *const *)value.constData()) { + valueType = o->metaObject()->className(); + + QQmlMetaObject propertyMetaObject = QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate::get(engine), type); + if (!propertyMetaObject.isNull()) + propertyType = propertyMetaObject.className(); + } + } else if (value.userType() != QVariant::Invalid) { + if (value.userType() == QMetaType::VoidStar) + valueType = "null"; + else + valueType = QMetaType::typeName(value.userType()); + } + + if (!valueType) + valueType = "undefined"; + if (!propertyType) + propertyType = QMetaType::typeName(type); + if (!propertyType) + propertyType = "[unknown property type]"; + + delayedError()->setErrorDescription(QLatin1String("Unable to assign ") + + QLatin1String(valueType) + + QLatin1String(" to ") + + QLatin1String(propertyType)); + return false; + } + + return true; } QVariant QQmlBinding::evaluate() { QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine); - QV4::Scope scope(ep->v4engine()); ep->referenceScarceResources(); bool isUndefined = false; - QV4::ScopedValue f(scope, v4function.value()); - QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(context(), f, &isUndefined)); + QV4::Scope scope(ep->v4engine()); + QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined)); ep->dereferenceScarceResources(); return scope.engine->toVariant(result, qMetaTypeId<QList<QObject*> >()); } -QString QQmlBinding::expressionIdentifier(QQmlJavaScriptExpression *e) +QString QQmlBinding::expressionIdentifier() { - QQmlBinding *This = static_cast<QQmlBinding *>(e); - - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(This->context()->engine); + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine); QV4::Scope scope(ep->v4engine()); - QV4::ScopedValue f(scope, This->v4function.value()); - QV4::Function *function = f->asFunctionObject()->function(); + QV4::ScopedValue f(scope, m_function.value()); + QV4::Function *function = f->as<QV4::FunctionObject>()->function(); QString url = function->sourceFile(); quint16 lineNumber = function->compiledFunction->location.line; @@ -254,10 +393,9 @@ QString QQmlBinding::expressionIdentifier(QQmlJavaScriptExpression *e) return url + QLatin1Char(':') + QString::number(lineNumber) + QLatin1Char(':') + QString::number(columnNumber); } -void QQmlBinding::expressionChanged(QQmlJavaScriptExpression *e) +void QQmlBinding::expressionChanged() { - QQmlBinding *This = static_cast<QQmlBinding *>(e); - This->update(); + update(); } void QQmlBinding::refresh() @@ -265,36 +403,6 @@ void QQmlBinding::refresh() update(); } -QString QQmlBinding::expression(const QQmlAbstractBinding *This) -{ - return static_cast<const QQmlBinding *>(This)->expression(); -} - -int QQmlBinding::propertyIndex(const QQmlAbstractBinding *This) -{ - return static_cast<const QQmlBinding *>(This)->propertyIndex(); -} - -QObject *QQmlBinding::object(const QQmlAbstractBinding *This) -{ - return static_cast<const QQmlBinding *>(This)->object(); -} - -void QQmlBinding::setEnabled(QQmlAbstractBinding *This, bool e, QQmlPropertyPrivate::WriteFlags f) -{ - static_cast<QQmlBinding *>(This)->setEnabled(e, f); -} - -void QQmlBinding::update(QQmlAbstractBinding *This , QQmlPropertyPrivate::WriteFlags f) -{ - static_cast<QQmlBinding *>(This)->update(f); -} - -void QQmlBinding::retargetBinding(QQmlAbstractBinding *This, QObject *o, int i) -{ - static_cast<QQmlBinding *>(This)->retargetBinding(o, i); -} - void QQmlBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags) { setEnabledFlag(e); @@ -307,44 +415,92 @@ void QQmlBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags) QString QQmlBinding::expression() const { QV4::Scope scope(QQmlEnginePrivate::get(context()->engine)->v4engine()); - QV4::ScopedValue v(scope, v4function.value()); + QV4::ScopedValue v(scope, m_function.value()); return v->toQStringNoThrow(); } -QObject *QQmlBinding::object() const +void QQmlBinding::setTarget(const QQmlProperty &prop) { - if (m_coreObject.hasValue()) return m_coreObject.constValue()->target; - else return *m_coreObject; + setTarget(prop.object(), QQmlPropertyPrivate::get(prop)->core); } -int QQmlBinding::propertyIndex() const +void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core) { - if (m_coreObject.hasValue()) return m_coreObject.constValue()->targetProperty; - else return m_core.encodedIndex(); -} + m_target = object; -void QQmlBinding::retargetBinding(QObject *t, int i) -{ - m_coreObject.value().target = t; - m_coreObject.value().targetProperty = i; -} + if (!object) { + m_targetIndex = -1; + return; + } -void QQmlBinding::setTarget(const QQmlProperty &prop) -{ - setTarget(prop.object(), QQmlPropertyPrivate::get(prop)->core, - QQmlPropertyPrivate::get(prop)->context); -} + QQmlPropertyData pd = core; -void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, QQmlContextData *ctxt) -{ - m_coreObject = object; - m_core = core; - m_ctxt = ctxt; + while (pd.isAlias()) { + int coreIndex = pd.coreIndex; + int valueTypeIndex = pd.getValueTypeCoreIndex(); + QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex); + + int aValueTypeIndex; + if (!vme->aliasTarget(coreIndex, &object, &coreIndex, &aValueTypeIndex)) { + m_target = 0; + m_targetIndex = -1; + return; + } + if (valueTypeIndex == -1) + valueTypeIndex = aValueTypeIndex; + + QQmlData *data = QQmlData::get(object, false); + if (!data || !data->propertyCache) { + m_target = 0; + m_targetIndex = -1; + return; + } + QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex); + Q_ASSERT(propertyData); + + m_target = object; + pd = *propertyData; + if (valueTypeIndex != -1) { + const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(pd.propType); + Q_ASSERT(valueTypeMetaObject); + QMetaProperty vtProp = valueTypeMetaObject->property(valueTypeIndex); + pd.setFlags(pd.getFlags() | QQmlPropertyData::IsValueTypeVirtual); + pd.valueTypeFlags = QQmlPropertyData::flagsForProperty(vtProp); + pd.valueTypePropType = vtProp.userType(); + pd.valueTypeCoreIndex = valueTypeIndex; + } + } + m_targetIndex = pd.encodedIndex(); + + QQmlData *data = QQmlData::get(*m_target, true); + if (!data->propertyCache) { + data->propertyCache = QQmlEnginePrivate::get(context()->engine)->cache(m_target->metaObject()); + data->propertyCache->addref(); + } } -QQmlProperty QQmlBinding::property() const +QQmlPropertyData QQmlBinding::getPropertyData() const { - return QQmlPropertyPrivate::restore(object(), m_core, *m_ctxt); + int coreIndex; + int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(m_targetIndex, &coreIndex); + + QQmlData *data = QQmlData::get(*m_target, false); + Q_ASSERT(data && data->propertyCache); + + QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex); + Q_ASSERT(propertyData); + + QQmlPropertyData d = *propertyData; + if (valueTypeIndex != -1) { + const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(d.propType); + Q_ASSERT(valueTypeMetaObject); + QMetaProperty vtProp = valueTypeMetaObject->property(valueTypeIndex); + d.setFlags(d.getFlags() | QQmlPropertyData::IsValueTypeVirtual); + d.valueTypeFlags = QQmlPropertyData::flagsForProperty(vtProp); + d.valueTypePropType = vtProp.userType(); + d.valueTypeCoreIndex = valueTypeIndex; + } + return d; } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h index 1e440b2e86..a435847819 100644 --- a/src/qml/qml/qqmlbinding_p.h +++ b/src/qml/qml/qqmlbinding_p.h @@ -57,16 +57,15 @@ #include <private/qpointervaluepair_p.h> #include <private/qqmlabstractbinding_p.h> -#include <private/qqmlabstractexpression_p.h> #include <private/qqmljavascriptexpression_p.h> QT_BEGIN_NAMESPACE class QQmlContext; class Q_QML_PRIVATE_EXPORT QQmlBinding : public QQmlJavaScriptExpression, - public QQmlAbstractExpression, public QQmlAbstractBinding { + friend class QQmlAbstractBinding; public: QQmlBinding(const QString &, QObject *, QQmlContext *); QQmlBinding(const QQmlScriptString &, QObject *, QQmlContext *); @@ -74,84 +73,62 @@ public: QQmlBinding(const QString &, QObject *, QQmlContextData *, const QString &url, quint16 lineNumber, quint16 columnNumber); QQmlBinding(const QV4::Value &, QObject *, QQmlContextData *); + ~QQmlBinding(); void setTarget(const QQmlProperty &); - void setTarget(QObject *, const QQmlPropertyData &, QQmlContextData *); - QQmlProperty property() const; + void setTarget(QObject *, const QQmlPropertyData &); void setNotifyOnValueChanged(bool); - // Inherited from QQmlAbstractExpression + // Inherited from QQmlJavaScriptExpression virtual void refresh(); - // "Inherited" from QQmlAbstractBinding - static QString expression(const QQmlAbstractBinding *); - static int propertyIndex(const QQmlAbstractBinding *); - static QObject *object(const QQmlAbstractBinding *); - static void setEnabled(QQmlAbstractBinding *, bool, QQmlPropertyPrivate::WriteFlags); - static void update(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags); - static void retargetBinding(QQmlAbstractBinding *, QObject *, int); - - void setEnabled(bool, QQmlPropertyPrivate::WriteFlags flags); - void update(QQmlPropertyPrivate::WriteFlags flags); - void update() { update(QQmlPropertyPrivate::DontRemoveBinding); } - - QString expression() const; - QObject *object() const; - int propertyIndex() const; - void retargetBinding(QObject *, int); + // Inherited from QQmlAbstractBinding + virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::DontRemoveBinding); + virtual QString expression() const; + void update(QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::DontRemoveBinding); typedef int Identifier; - static Identifier Invalid; + enum { + Invalid = -1 + }; QVariant evaluate(); - static QString expressionIdentifier(QQmlJavaScriptExpression *); - static void expressionChanged(QQmlJavaScriptExpression *); - -protected: - friend class QQmlAbstractBinding; - ~QQmlBinding(); + virtual QString expressionIdentifier(); + virtual void expressionChanged(); private: - QV4::PersistentValue v4function; - inline bool updatingFlag() const; inline void setUpdatingFlag(bool); inline bool enabledFlag() const; inline void setEnabledFlag(bool); + QQmlPropertyData getPropertyData() const; - struct Retarget { - QObject *target; - int targetProperty; - }; + bool write(const QQmlPropertyData &core, + const QV4::Value &result, bool isUndefined, + QQmlPropertyPrivate::WriteFlags flags); - QPointerValuePair<QObject, Retarget> m_coreObject; - QQmlPropertyData m_core; - // We store some flag bits in the following flag pointers. - // m_ctxt:flag1 - updatingFlag - // m_ctxt:flag2 - enabledFlag - QFlagPointer<QQmlContextData> m_ctxt; }; bool QQmlBinding::updatingFlag() const { - return m_ctxt.flag(); + return m_target.flag(); } void QQmlBinding::setUpdatingFlag(bool v) { - m_ctxt.setFlagValue(v); + m_target.setFlagValue(v); } bool QQmlBinding::enabledFlag() const { - return m_ctxt.flag2(); + return m_target.flag2(); } void QQmlBinding::setEnabledFlag(bool v) { - m_ctxt.setFlag2Value(v); + m_target.setFlag2Value(v); } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index 766e657c59..3d1a9f8a88 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -43,11 +43,12 @@ #include "qqmlcontext.h" #include "qqmlglobal_p.h" #include <private/qqmlprofiler_p.h> -#include <private/qv4debugservice_p.h> +#include <private/qqmldebugconnector_p.h> +#include <private/qqmldebugserviceinterfaces_p.h> #include <private/qqmlcompiler_p.h> #include "qqmlinfo.h" -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <QtCore/qstringbuilder.h> #include <QtCore/qdebug.h> @@ -55,59 +56,68 @@ QT_BEGIN_NAMESPACE -static QQmlJavaScriptExpression::VTable QQmlBoundSignalExpression_jsvtable = { - QQmlBoundSignalExpression::expressionIdentifier, - QQmlBoundSignalExpression::expressionChanged -}; - -QQmlBoundSignalExpression::ExtraData::ExtraData(const QString &handlerName, const QString ¶meterString, - const QString &expression, const QString &fileName, - quint16 line, quint16 column) - : m_handlerName(handlerName), - m_parameterString(parameterString), - m_expression(expression), - m_sourceLocation(fileName, line, column) -{ -} - QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, const QString &expression, const QString &fileName, quint16 line, quint16 column, const QString &handlerName, const QString ¶meterString) - : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable), + : QQmlJavaScriptExpression(), m_index(index), - m_target(target), - m_extra(new ExtraData(handlerName, parameterString, expression, fileName, line, column)) + m_target(target) { - setExpressionFunctionValid(false); - setInvalidParameterName(false); - init(ctxt, scope); + + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine()); + QV4::ExecutionEngine *v4 = ep->v4engine(); + + QString function; + + // Add some leading whitespace to account for the binding's column offset. + // It's 2 off because a, we start counting at 1 and b, the '(' below is not counted. + function.fill(QChar(QChar::Space), qMax(column, (quint16)2) - 2); + function += QStringLiteral("(function "); + function += handlerName; + function += QLatin1Char('('); + + if (parameterString.isEmpty()) { + QString error; + //TODO: look at using the property cache here (as in the compiler) + // for further optimization + QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index); + function += QQmlPropertyCache::signalParameterStringForJS(v4, signal.parameterNames(), &error); + + if (!error.isEmpty()) { + qmlInfo(scopeObject()) << error; + return; + } + } else + function += parameterString; + + function += QStringLiteral(") { "); + function += expression; + function += QStringLiteral(" })"); + + m_function.set(v4, evalFunction(context(), scopeObject(), function, fileName, line)); + + if (m_function.isNullOrUndefined()) + return; // could not evaluate function. Not valid. + } QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, const QV4::Value &function) - : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable), + : QQmlJavaScriptExpression(), m_index(index), - m_function(function.asObject()->engine(), function), - m_target(target), - m_extra(0) + m_target(target) { - setExpressionFunctionValid(true); - setInvalidParameterName(false); - + m_function.set(function.as<QV4::Object>()->engine(), function); init(ctxt, scope); } QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, QV4::Function *runtimeFunction) - : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable), + : QQmlJavaScriptExpression(), m_index(index), - m_target(target), - m_extra(0) + m_target(target) { - setExpressionFunctionValid(true); - setInvalidParameterName(false); - // It's important to call init first, because m_index gets remapped in case of cloned signals. init(ctxt, scope); @@ -117,9 +127,8 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, m_function.set(engine, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxt, scope, runtimeFunction, signal.parameterNames(), &error)); if (!error.isEmpty()) { qmlInfo(scopeObject()) << error; - setInvalidParameterName(true); - } else - setInvalidParameterName(false); + m_function.clear(); + } } void QQmlBoundSignalExpression::init(QQmlContextData *ctxt, QObject *scope) @@ -134,34 +143,30 @@ void QQmlBoundSignalExpression::init(QQmlContextData *ctxt, QObject *scope) QQmlBoundSignalExpression::~QQmlBoundSignalExpression() { - delete m_extra.data(); } -QString QQmlBoundSignalExpression::expressionIdentifier(QQmlJavaScriptExpression *e) +QString QQmlBoundSignalExpression::expressionIdentifier() { - QQmlBoundSignalExpression *This = static_cast<QQmlBoundSignalExpression *>(e); - QQmlSourceLocation loc = This->sourceLocation(); + QQmlSourceLocation loc = sourceLocation(); return loc.sourceFile + QLatin1Char(':') + QString::number(loc.line); } -void QQmlBoundSignalExpression::expressionChanged(QQmlJavaScriptExpression *) +void QQmlBoundSignalExpression::expressionChanged() { // bound signals do not notify on change. } QQmlSourceLocation QQmlBoundSignalExpression::sourceLocation() const { - if (expressionFunctionValid()) { - QV4::Function *f = function(); - Q_ASSERT(f); + QV4::Function *f = function(); + if (f) { QQmlSourceLocation loc; loc.sourceFile = f->sourceFile(); loc.line = f->compiledFunction->location.line; loc.column = f->compiledFunction->location.column; return loc; } - Q_ASSERT(!m_extra.isNull()); - return m_extra->m_sourceLocation; + return QQmlSourceLocation(); } QString QQmlBoundSignalExpression::expression() const @@ -171,10 +176,8 @@ QString QQmlBoundSignalExpression::expression() const QV4::Scope scope(QQmlEnginePrivate::get(engine())->v4engine()); QV4::ScopedValue v(scope, m_function.value()); return v->toQStringNoThrow(); - } else { - Q_ASSERT(!m_extra.isNull()); - return m_extra->m_expression; } + return QString(); } QV4::Function *QQmlBoundSignalExpression::function() const @@ -194,108 +197,79 @@ void QQmlBoundSignalExpression::evaluate(void **a) { Q_ASSERT (context() && engine()); - if (invalidParameterName()) + if (!expressionFunctionValid()) return; QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine()); QV4::Scope scope(ep->v4engine()); ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation. - { - if (!expressionFunctionValid()) { - Q_ASSERT(!m_extra.isNull()); - QString expression; - - // Add some leading whitespace to account for the binding's column offset. - // It's 2 off because a, we start counting at 1 and b, the '(' below is not counted. - expression.fill(QChar(QChar::Space), qMax(m_extra->m_sourceLocation.column, (quint16)2) - 2); - expression += QStringLiteral("(function "); - expression += m_extra->m_handlerName; - expression += QLatin1Char('('); - - if (m_extra->m_parameterString.isEmpty()) { - QString error; - //TODO: look at using the property cache here (as in the compiler) - // for further optimization - QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index); - expression += QQmlPropertyCache::signalParameterStringForJS(scope.engine, signal.parameterNames(), &error); - - if (!error.isEmpty()) { - qmlInfo(scopeObject()) << error; - setInvalidParameterName(true); - ep->dereferenceScarceResources(); - return; - } - } else - expression += m_extra->m_parameterString; - - expression += QStringLiteral(") { "); - expression += m_extra->m_expression; - expression += QStringLiteral(" })"); - - m_extra->m_expression.clear(); - m_extra->m_handlerName.clear(); - m_extra->m_parameterString.clear(); - - m_function.set(scope.engine, evalFunction(context(), scopeObject(), expression, - m_extra->m_sourceLocation.sourceFile, m_extra->m_sourceLocation.line, &m_extra->m_v8qmlscope)); - - if (m_function.isNullOrUndefined()) { - ep->dereferenceScarceResources(); - return; // could not evaluate function. Not valid. - } - - setExpressionFunctionValid(true); - } - QVarLengthArray<int, 9> dummy; - //TODO: lookup via signal index rather than method index as an optimization - int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex(); - int *argsTypes = QQmlMetaObject(m_target).methodParameterTypes(methodIndex, dummy, 0); - int argCount = argsTypes ? *argsTypes : 0; - - QV4::ScopedValue f(scope, m_function.value()); - QV4::ScopedCallData callData(scope, argCount); - for (int ii = 0; ii < argCount; ++ii) { - int type = argsTypes[ii + 1]; - //### ideally we would use metaTypeToJS, however it currently gives different results - // for several cases (such as QVariant type and QObject-derived types) - //args[ii] = engine->metaTypeToJS(type, a[ii + 1]); - if (type == QMetaType::QVariant) { - callData->args[ii] = scope.engine->fromVariant(*((QVariant *)a[ii + 1])); - } else if (type == QMetaType::Int) { - //### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise - callData->args[ii] = QV4::Primitive::fromInt32(*reinterpret_cast<const int*>(a[ii + 1])); - } else if (type == qMetaTypeId<QQmlV4Handle>()) { - callData->args[ii] = *reinterpret_cast<QQmlV4Handle *>(a[ii + 1]); - } else if (ep->isQObject(type)) { - if (!*reinterpret_cast<void* const *>(a[ii + 1])) - callData->args[ii] = QV4::Primitive::nullValue(); - else - callData->args[ii] = QV4::QObjectWrapper::wrap(ep->v4engine(), *reinterpret_cast<QObject* const *>(a[ii + 1])); - } else { - callData->args[ii] = scope.engine->fromVariant(QVariant(type, a[ii + 1])); - } + QVarLengthArray<int, 9> dummy; + //TODO: lookup via signal index rather than method index as an optimization + int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex(); + int *argsTypes = QQmlMetaObject(m_target).methodParameterTypes(methodIndex, dummy, 0); + int argCount = argsTypes ? *argsTypes : 0; + + QV4::ScopedCallData callData(scope, argCount); + for (int ii = 0; ii < argCount; ++ii) { + int type = argsTypes[ii + 1]; + //### ideally we would use metaTypeToJS, however it currently gives different results + // for several cases (such as QVariant type and QObject-derived types) + //args[ii] = engine->metaTypeToJS(type, a[ii + 1]); + if (type == QMetaType::QVariant) { + callData->args[ii] = scope.engine->fromVariant(*((QVariant *)a[ii + 1])); + } else if (type == QMetaType::Int) { + //### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise + callData->args[ii] = QV4::Primitive::fromInt32(*reinterpret_cast<const int*>(a[ii + 1])); + } else if (type == qMetaTypeId<QQmlV4Handle>()) { + callData->args[ii] = *reinterpret_cast<QQmlV4Handle *>(a[ii + 1]); + } else if (ep->isQObject(type)) { + if (!*reinterpret_cast<void* const *>(a[ii + 1])) + callData->args[ii] = QV4::Primitive::nullValue(); + else + callData->args[ii] = QV4::QObjectWrapper::wrap(ep->v4engine(), *reinterpret_cast<QObject* const *>(a[ii + 1])); + } else { + callData->args[ii] = scope.engine->fromVariant(QVariant(type, a[ii + 1])); } - - QQmlJavaScriptExpression::evaluate(context(), f, callData, 0); } + + QQmlJavaScriptExpression::evaluate(callData, 0); + ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. } //////////////////////////////////////////////////////////////////////// -QQmlAbstractBoundSignal::QQmlAbstractBoundSignal() -: m_prevSignal(0), m_nextSignal(0) + +/*! \internal + \a signal MUST be in the signal index range (see QObjectPrivate::signalIndex()). + This is different from QMetaMethod::methodIndex(). +*/ +QQmlBoundSignal::QQmlBoundSignal(QObject *target, int signal, QObject *owner, + QQmlEngine *engine) + : QQmlNotifierEndpoint(QQmlNotifierEndpoint::QQmlBoundSignal), + m_prevSignal(0), m_nextSignal(0), + m_expression(0) { + addToObject(owner); + + /* + If this is a cloned method, connect to the 'original'. For example, + for the signal 'void aSignal(int parameter = 0)', if the method + index refers to 'aSignal()', get the index of 'aSignal(int)'. + This ensures that 'parameter' will be available from QML. + */ + signal = QQmlPropertyCache::originalClone(target, signal); + QQmlNotifierEndpoint::connect(target, signal, engine); } -QQmlAbstractBoundSignal::~QQmlAbstractBoundSignal() +QQmlBoundSignal::~QQmlBoundSignal() { removeFromObject(); } -void QQmlAbstractBoundSignal::addToObject(QObject *obj) +void QQmlBoundSignal::addToObject(QObject *obj) { Q_ASSERT(!m_prevSignal); Q_ASSERT(obj); @@ -308,7 +282,7 @@ void QQmlAbstractBoundSignal::addToObject(QObject *obj) data->signalHandlers = this; } -void QQmlAbstractBoundSignal::removeFromObject() +void QQmlBoundSignal::removeFromObject() { if (m_prevSignal) { *m_prevSignal = m_nextSignal; @@ -318,40 +292,6 @@ void QQmlAbstractBoundSignal::removeFromObject() } } -/*! \internal - \a signal MUST be in the signal index range (see QObjectPrivate::signalIndex()). - This is different from QMetaMethod::methodIndex(). -*/ -QQmlBoundSignal::QQmlBoundSignal(QObject *target, int signal, QObject *owner, - QQmlEngine *engine) -: m_expression(0), m_index(signal), m_isEvaluating(false) -{ - addToObject(owner); - setCallback(QQmlNotifierEndpoint::QQmlBoundSignal); - - /* - If this is a cloned method, connect to the 'original'. For example, - for the signal 'void aSignal(int parameter = 0)', if the method - index refers to 'aSignal()', get the index of 'aSignal(int)'. - This ensures that 'parameter' will be available from QML. - */ - m_index = QQmlPropertyCache::originalClone(target, m_index); - QQmlNotifierEndpoint::connect(target, m_index, engine); -} - -QQmlBoundSignal::~QQmlBoundSignal() -{ - m_expression = 0; -} - -/*! - Returns the signal index in the range returned by QObjectPrivate::signalIndex(). - This is different from QMetaMethod::methodIndex(). -*/ -int QQmlBoundSignal::index() const -{ - return m_index; -} /*! Returns the signal expression. @@ -362,45 +302,29 @@ QQmlBoundSignalExpression *QQmlBoundSignal::expression() const } /*! - Sets the signal expression to \a e. Returns the current signal expression, - or null if there is no signal expression. + Sets the signal expression to \a e. - The QQmlBoundSignal instance adds a reference to \a e. The caller - assumes ownership of the returned QQmlBoundSignalExpression reference. + The QQmlBoundSignal instance takes ownership of \a e (and does not add a reference). */ -QQmlBoundSignalExpressionPointer QQmlBoundSignal::setExpression(QQmlBoundSignalExpression *e) +void QQmlBoundSignal::takeExpression(QQmlBoundSignalExpression *e) { - QQmlBoundSignalExpressionPointer rv = m_expression; - m_expression = e; - if (m_expression) m_expression->setNotifyOnValueChanged(false); - return rv; -} - -/*! - Sets the signal expression to \a e. Returns the current signal expression, - or null if there is no signal expression. - - The QQmlBoundSignal instance takes ownership of \a e (and does not add a reference). The caller - assumes ownership of the returned QQmlBoundSignalExpression reference. -*/ -QQmlBoundSignalExpressionPointer QQmlBoundSignal::takeExpression(QQmlBoundSignalExpression *e) -{ - QQmlBoundSignalExpressionPointer rv = m_expression; m_expression.take(e); - if (m_expression) m_expression->setNotifyOnValueChanged(false); - return rv; + if (m_expression) + m_expression->setNotifyOnValueChanged(false); } void QQmlBoundSignal_callback(QQmlNotifierEndpoint *e, void **a) { QQmlBoundSignal *s = static_cast<QQmlBoundSignal*>(e); + if (!s->m_expression) return; - if (QQmlDebugService::isDebuggingEnabled()) - QV4DebugService::instance()->signalEmitted(QString::fromLatin1(QMetaObjectPrivate::signal(s->m_expression->target()->metaObject(), s->m_index).methodSignature())); - - s->m_isEvaluating = true; + QV4DebugService *service = QQmlDebugConnector::service<QV4DebugService>(); + if (service) + service->signalEmitted(QString::fromLatin1(QMetaObjectPrivate::signal( + s->m_expression->target()->metaObject(), + s->signalIndex()).methodSignature())); QQmlEngine *engine; if (s->m_expression && (engine = s->m_expression->engine())) { @@ -410,8 +334,6 @@ void QQmlBoundSignal_callback(QQmlNotifierEndpoint *e, void **a) QQmlEnginePrivate::warning(engine, s->m_expression->error(engine)); } } - - s->m_isEvaluating = false; } //////////////////////////////////////////////////////////////////////// diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h index 8d677ea039..3742317484 100644 --- a/src/qml/qml/qqmlboundsignal_p.h +++ b/src/qml/qml/qqmlboundsignal_p.h @@ -47,7 +47,6 @@ #include <QtCore/qmetaobject.h> -#include <private/qqmlabstractexpression_p.h> #include <private/qqmljavascriptexpression_p.h> #include <private/qqmlboundsignalexpressionpointer_p.h> #include <private/qqmlnotifier_p.h> @@ -58,7 +57,7 @@ QT_BEGIN_NAMESPACE -class Q_QML_PRIVATE_EXPORT QQmlBoundSignalExpression : public QQmlAbstractExpression, public QQmlJavaScriptExpression, public QQmlRefCount +class Q_QML_PRIVATE_EXPORT QQmlBoundSignalExpression : public QQmlJavaScriptExpression, public QQmlRefCount { public: QQmlBoundSignalExpression(QObject *target, int index, @@ -73,9 +72,9 @@ public: QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, QV4::Function *runtimeFunction); - // "inherited" from QQmlJavaScriptExpression. - static QString expressionIdentifier(QQmlJavaScriptExpression *); - static void expressionChanged(QQmlJavaScriptExpression *); + // inherited from QQmlJavaScriptExpression. + virtual QString expressionIdentifier(); + virtual void expressionChanged(); // evaluation of a bound signal expression doesn't return any value void evaluate(void **a); @@ -92,80 +91,35 @@ private: void init(QQmlContextData *ctxt, QObject *scope); - bool expressionFunctionValid() const { return m_extra.flag(); } - void setExpressionFunctionValid(bool v) { m_extra.setFlagValue(v); } - - bool invalidParameterName() const { return m_extra.flag2(); } - void setInvalidParameterName(bool v) { m_extra.setFlag2Value(v); } + bool expressionFunctionValid() const { return !m_function.isNullOrUndefined(); } int m_index; - QV4::PersistentValue m_function; - QObject *m_target; - - // only needed when !expressionFunctionValid() - struct ExtraData { - ExtraData(const QString &handlerName, const QString ¶meterString, - const QString &expression, const QString &fileName, - quint16 line, quint16 column); - QString m_handlerName; - QString m_parameterString; - QString m_expression; - QQmlSourceLocation m_sourceLocation; - QV4::PersistentValue m_v8qmlscope; - }; - - // We store some flag bits in the following flag pointers. - // flag - expressionFunctionValid - // flag2 - invalidParameterName - QFlagPointer<ExtraData> m_extra; }; -class Q_QML_PRIVATE_EXPORT QQmlAbstractBoundSignal +class Q_QML_PRIVATE_EXPORT QQmlBoundSignal : public QQmlNotifierEndpoint { public: - QQmlAbstractBoundSignal(); - virtual ~QQmlAbstractBoundSignal(); - - virtual int index() const = 0; - virtual QQmlBoundSignalExpression *expression() const = 0; - virtual QQmlBoundSignalExpressionPointer setExpression(QQmlBoundSignalExpression *) = 0; - virtual QQmlBoundSignalExpressionPointer takeExpression(QQmlBoundSignalExpression *) = 0; - virtual bool isEvaluating() const = 0; + QQmlBoundSignal(QObject *target, int signal, QObject *owner, QQmlEngine *engine); + ~QQmlBoundSignal(); void removeFromObject(); -protected: - void addToObject(QObject *owner); + + QQmlBoundSignalExpression *expression() const; + void takeExpression(QQmlBoundSignalExpression *); private: - friend class QQmlData; + friend void QQmlBoundSignal_callback(QQmlNotifierEndpoint *, void **); friend class QQmlPropertyPrivate; + friend class QQmlData; friend class QQmlEngineDebugService; - QQmlAbstractBoundSignal **m_prevSignal; - QQmlAbstractBoundSignal *m_nextSignal; -}; -class Q_QML_PRIVATE_EXPORT QQmlBoundSignal : public QQmlAbstractBoundSignal, - public QQmlNotifierEndpoint -{ -public: - QQmlBoundSignal(QObject *target, int signal, QObject *owner, QQmlEngine *engine); - virtual ~QQmlBoundSignal(); - - int index() const; - - QQmlBoundSignalExpression *expression() const; - QQmlBoundSignalExpressionPointer setExpression(QQmlBoundSignalExpression *); - QQmlBoundSignalExpressionPointer takeExpression(QQmlBoundSignalExpression *); + void addToObject(QObject *owner); - bool isEvaluating() const { return m_isEvaluating; } - -private: - friend void QQmlBoundSignal_callback(QQmlNotifierEndpoint *, void **); + QQmlBoundSignal **m_prevSignal; + QQmlBoundSignal *m_nextSignal; QQmlBoundSignalExpressionPointer m_expression; - int m_index; - bool m_isEvaluating; }; QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 9210610cec..d62aada9c6 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -43,7 +43,8 @@ #include "qqmlengine.h" #include "qqmlbinding_p.h" #include "qqmlglobal_p.h" -#include <private/qqmlenginedebugservice_p.h> +#include <private/qqmldebugconnector_p.h> +#include <private/qqmldebugserviceinterfaces_p.h> #include "qqmlincubator.h" #include "qqmlincubator_p.h" #include <private/qqmljavascriptexpression_p.h> @@ -53,6 +54,7 @@ #include <private/qv4functionobject_p.h> #include <private/qv4script_p.h> #include <private/qv4scopedvalue_p.h> +#include <private/qv4objectiterator_p.h> #include <QStack> #include <QStringList> @@ -61,23 +63,6 @@ #include <qqmlinfo.h> #include "qqmlmemoryprofiler_p.h" -#define INITIALPROPERTIES_SOURCE \ - "(function(object, values) {"\ - "try {"\ - "for (var property in values) {" \ - "try {"\ - "var properties = property.split(\".\");"\ - "var o = object;"\ - "for (var ii = 0; ii < properties.length - 1; ++ii) {"\ - "o = o[properties[ii]];"\ - "}"\ - "o[properties[properties.length - 1]] = values[property];"\ - "} catch(e) {}"\ - "}"\ - "} catch(e) {}"\ - "})" - - namespace { QThreadStorage<int> creationDepth; } @@ -98,7 +83,6 @@ V4_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension); \class QQmlComponent \since 5.0 \inmodule QtQml - \mainclass \brief The QQmlComponent class encapsulates a QML component definition @@ -896,10 +880,11 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context) depthIncreased = false; } - if (enginePriv->isDebugging && rv) { + QQmlEngineDebugService *service = QQmlDebugConnector::service<QQmlEngineDebugService>(); + if (service && rv) { if (!context->isInternal) context->asQQmlContextPrivate()->instances.append(rv); - QQmlEngineDebugService::instance()->objectCreated(engine, rv); + service->objectCreated(engine, rv); } return rv; @@ -1194,6 +1179,46 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent) \sa incubateObject() */ + +static void setInitialProperties(QV4::ExecutionEngine *engine, const QV4::Value &o, const QV4::Value &v) +{ + QV4::Scope scope(engine); + QV4::ScopedObject object(scope); + QV4::ScopedObject valueMap(scope, v); + QV4::ObjectIterator it(scope, valueMap, QV4::ObjectIterator::EnumerableOnly|QV4::ObjectIterator::WithProtoChain); + QV4::ScopedString name(scope); + QV4::ScopedValue val(scope); + if (engine->hasException) + return; + + while (1) { + name = it.nextPropertyNameAsString(val); + if (!name) + break; + object = o; + const QStringList properties = name->toQString().split(QLatin1Char('.')); + for (int i = 0; i < properties.length() - 1; ++i) { + name = engine->newString(properties.at(i)); + object = object->get(name); + if (engine->hasException || !object) { + break; + } + } + if (engine->hasException || !object) { + engine->hasException = false; + continue; + } + name = engine->newString(properties.last()); + object->put(name, val); + if (engine->hasException) { + engine->hasException = false; + continue; + } + } + + engine->hasException = false; +} + /*! \internal */ @@ -1216,7 +1241,7 @@ void QQmlComponent::createObject(QQmlV4Function *args) if (args->length() >= 2) { QV4::ScopedValue v(scope, (*args)[1]); - if (!v->asObject() || v->asArrayObject()) { + if (!v->as<QV4::Object>() || v->as<QV4::ArrayObject>()) { qmlInfo(this) << tr("createObject: value is not an object"); args->setReturnValue(QV4::Encode::null()); return; @@ -1239,16 +1264,8 @@ void QQmlComponent::createObject(QQmlV4Function *args) QV4::ScopedValue object(scope, QV4::QObjectWrapper::wrap(v4, rv)); Q_ASSERT(object->isObject()); - if (!valuemap->isUndefined()) { - QV4::ScopedObject qmlglobal(scope, args->qmlGlobal()); - QV4::ScopedValue f(scope, QV4::Script::evaluate(v4, QString::fromLatin1(INITIALPROPERTIES_SOURCE), qmlglobal)); - Q_ASSERT(f->asFunctionObject()); - QV4::ScopedCallData callData(scope, 2); - callData->thisObject = v4->globalObject(); - callData->args[0] = object; - callData->args[1] = valuemap; - f->asFunctionObject()->call(callData); - } + if (!valuemap->isUndefined()) + setInitialProperties(v4, object, valuemap); d->completeCreate(); @@ -1256,10 +1273,7 @@ void QQmlComponent::createObject(QQmlV4Function *args) QQmlData::get(rv)->explicitIndestructibleSet = false; QQmlData::get(rv)->indestructible = false; - if (!rv) - args->setReturnValue(QV4::Encode::null()); - else - args->setReturnValue(object->asReturnedValue()); + args->setReturnValue(object->asReturnedValue()); } /*! @@ -1342,7 +1356,7 @@ void QQmlComponent::incubateObject(QQmlV4Function *args) if (args->length() >= 2) { QV4::ScopedValue v(scope, (*args)[1]); if (v->isNull()) { - } else if (!v->asObject() || v->asArrayObject()) { + } else if (!v->as<QV4::Object>() || v->as<QV4::ArrayObject>()) { qmlInfo(this) << tr("createObject: value is not an object"); args->setReturnValue(QV4::Encode::null()); return; @@ -1383,25 +1397,17 @@ void QQmlComponent::incubateObject(QQmlV4Function *args) } // XXX used by QSGLoader -void QQmlComponentPrivate::initializeObjectWithInitialProperties(const QV4::Value &qmlGlobal, const QV4::Value &valuemap, QObject *toCreate) +void QQmlComponentPrivate::initializeObjectWithInitialProperties(const QV4::Value &valuemap, QObject *toCreate) { QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); QV4::ExecutionEngine *v4engine = QV8Engine::getV4(ep->v8engine()); QV4::Scope scope(v4engine); QV4::ScopedValue object(scope, QV4::QObjectWrapper::wrap(v4engine, toCreate)); - Q_ASSERT(object->asObject()); - - if (!valuemap.isUndefined()) { - QV4::ScopedObject qmlGlobalObj(scope, qmlGlobal); - QV4::ScopedFunctionObject f(scope, QV4::Script::evaluate(v4engine, - QString::fromLatin1(INITIALPROPERTIES_SOURCE), qmlGlobalObj)); - QV4::ScopedCallData callData(scope, 2); - callData->thisObject = v4engine->globalObject(); - callData->args[0] = object; - callData->args[1] = valuemap; - f->call(callData); - } + Q_ASSERT(object->as<QV4::Object>()); + + if (!valuemap.isUndefined()) + setInitialProperties(v4engine, object, valuemap); } QQmlComponentExtension::QQmlComponentExtension(QV4::ExecutionEngine *v4) @@ -1491,13 +1497,8 @@ void QV4::QmlIncubatorObject::setInitialState(QObject *o) if (!d()->valuemap.isUndefined()) { QV4::ExecutionEngine *v4 = engine(); QV4::Scope scope(v4); - - QV4::ScopedFunctionObject f(scope, QV4::Script::evaluate(v4, QString::fromLatin1(INITIALPROPERTIES_SOURCE), d()->qmlGlobal.asObject())); - QV4::ScopedCallData callData(scope, 2); - callData->thisObject = v4->globalObject(); - callData->args[0] = QV4::QObjectWrapper::wrap(v4, o); - callData->args[1] = d()->valuemap; - f->call(callData); + QV4::ScopedObject obj(scope, QV4::QObjectWrapper::wrap(v4, o)); + setInitialProperties(v4, obj, d()->valuemap); } } diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h index 8c866c585a..121c83db5c 100644 --- a/src/qml/qml/qqmlcomponent.h +++ b/src/qml/qml/qqmlcomponent.h @@ -63,8 +63,8 @@ class Q_QML_EXPORT QQmlComponent : public QObject Q_PROPERTY(QUrl url READ url CONSTANT) public: - Q_ENUMS(CompilationMode) enum CompilationMode { PreferSynchronous, Asynchronous }; + Q_ENUM(CompilationMode) QQmlComponent(QObject *parent = 0); QQmlComponent(QQmlEngine *, QObject *parent=0); @@ -74,8 +74,8 @@ public: QQmlComponent(QQmlEngine *, const QUrl &url, CompilationMode mode, QObject *parent = 0); virtual ~QQmlComponent(); - Q_ENUMS(Status) enum Status { Null, Ready, Loading, Error }; + Q_ENUM(Status) Status status() const; bool isNull() const; @@ -125,7 +125,6 @@ private: QT_END_NAMESPACE -Q_DECLARE_METATYPE(QQmlComponent::Status) QML_DECLARE_TYPE(QQmlComponent) QML_DECLARE_TYPEINFO(QQmlComponent, QML_HAS_ATTACHED_PROPERTIES) diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h index adc6e173d2..15ec88dd52 100644 --- a/src/qml/qml/qqmlcomponent_p.h +++ b/src/qml/qml/qqmlcomponent_p.h @@ -82,7 +82,7 @@ public: QObject *beginCreate(QQmlContextData *); void completeCreate(); - void initializeObjectWithInitialProperties(const QV4::Value &qmlGlobal, const QV4::Value &valuemap, QObject *toCreate); + void initializeObjectWithInitialProperties(const QV4::Value &valuemap, QObject *toCreate); QQmlTypeData *typeData; virtual void typeDataReady(QQmlTypeData *); diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp index fb51bad3a7..b056731e96 100644 --- a/src/qml/qml/qqmlcontext.cpp +++ b/src/qml/qml/qqmlcontext.cpp @@ -57,7 +57,6 @@ QQmlContextPrivate::QQmlContextPrivate() /*! \class QQmlContext \brief The QQmlContext class defines a context within a QML engine. - \mainclass \inmodule QtQml Contexts allow data to be exposed to the QML components instantiated by the @@ -585,9 +584,9 @@ void QQmlContextData::clearContext() { emitDestruction(); - QQmlAbstractExpression *expression = expressions; + QQmlJavaScriptExpression *expression = expressions; while (expression) { - QQmlAbstractExpression *nextExpression = expression->m_nextExpression; + QQmlJavaScriptExpression *nextExpression = expression->m_nextExpression; expression->m_prevExpression = 0; expression->m_nextExpression = 0; @@ -652,9 +651,9 @@ void QQmlContextData::setParent(QQmlContextData *p, bool parentTakesOwnership) } } -void QQmlContextData::refreshExpressionsRecursive(QQmlAbstractExpression *expression) +void QQmlContextData::refreshExpressionsRecursive(QQmlJavaScriptExpression *expression) { - QQmlAbstractExpression::DeleteWatcher w(expression); + QQmlJavaScriptExpression::DeleteWatcher w(expression); if (expression->m_nextExpression) refreshExpressionsRecursive(expression->m_nextExpression); @@ -808,7 +807,7 @@ QV4::IdentifierHash<int> &QQmlContextData::propertyNames() const { if (propertyNameCache.isEmpty()) { propertyNameCache = QV4::IdentifierHash<int>(QV8Engine::getV4(engine->handle())); - for (QHash<int, int>::ConstIterator it = objectIndexToId.begin(), end = objectIndexToId.end(); + for (QHash<int, int>::ConstIterator it = objectIndexToId.cbegin(), end = objectIndexToId.cend(); it != end; ++it) { const QV4::CompiledData::Object *obj = typeCompilationUnit->data->objectAt(it.key()); const QString name = typeCompilationUnit->data->stringAt(obj->idIndex); diff --git a/src/qml/qml/qqmlcontext.h b/src/qml/qml/qqmlcontext.h index c714846147..e69a2f8f69 100644 --- a/src/qml/qml/qqmlcontext.h +++ b/src/qml/qml/qqmlcontext.h @@ -72,6 +72,7 @@ public: void setContextProperty(const QString &, QObject *); void setContextProperty(const QString &, const QVariant &); + // ### Qt 6: no need for a mutable object, this should become a const QObject pointer QString nameForObject(QObject *) const; QUrl resolvedUrl(const QUrl &); diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h index f5fd7d0a5c..95254d4baa 100644 --- a/src/qml/qml/qqmlcontext_p.h +++ b/src/qml/qml/qqmlcontext_p.h @@ -69,7 +69,7 @@ class QQmlExpression; class QQmlEngine; class QQmlExpression; class QQmlExpressionPrivate; -class QQmlAbstractExpression; +class QQmlJavaScriptExpression; class QQmlContextData; class QQmlContextPrivate : public QObjectPrivate @@ -171,7 +171,7 @@ public: QQmlContextData **prevChild; // Expressions that use this context - QQmlAbstractExpression *expressions; + QQmlJavaScriptExpression *expressions; // Doubly-linked list of objects that are owned by this context QQmlData *contextObjects; @@ -212,7 +212,7 @@ public: private: void refreshExpressionsRecursive(bool isGlobal); - void refreshExpressionsRecursive(QQmlAbstractExpression *); + void refreshExpressionsRecursive(QQmlJavaScriptExpression *); ~QQmlContextData() {} }; diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp index 5844eab54f..23084fb202 100644 --- a/src/qml/qml/qqmlcontextwrapper.cpp +++ b/src/qml/qml/qqmlcontextwrapper.cpp @@ -38,13 +38,14 @@ #include <private/qqmlcontext_p.h> #include <private/qv4engine_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4objectproto_p.h> #include <private/qv4mm_p.h> #include <private/qv4function_p.h> #include <private/qv4compileddata_p.h> #include <private/qqmltypewrapper_p.h> #include <private/qqmllistwrapper_p.h> +#include <private/qqmljavascriptexpression_p.h> #include <private/qjsvalue_p.h> QT_BEGIN_NAMESPACE @@ -60,7 +61,6 @@ Heap::QmlContextWrapper::QmlContextWrapper(QV4::ExecutionEngine *engine, QQmlCon , isNullWrapper(false) , context(context) , scopeObject(scopeObject) - , idObjectsWrapper(Q_NULLPTR) { } @@ -93,49 +93,30 @@ ReturnedValue QmlContextWrapper::urlScope(ExecutionEngine *v4, const QUrl &url) return w.asReturnedValue(); } -QQmlContextData *QmlContextWrapper::callingContext(ExecutionEngine *v4) -{ - Scope scope(v4); - QV4::Scoped<QmlContextWrapper> c(scope, v4->qmlContextObject()); - - return !!c ? c->getContext() : 0; -} - QQmlContextData *QmlContextWrapper::getContext(const Value &value) { if (!value.isObject()) return 0; - QV4::ExecutionEngine *v4 = value.asObject()->engine(); + QV4::ExecutionEngine *v4 = value.as<Object>()->engine(); Scope scope(v4); QV4::Scoped<QmlContextWrapper> c(scope, value); return c ? c->getContext() : 0; } -void QmlContextWrapper::takeContextOwnership(const Value &qmlglobal) -{ - Q_ASSERT(qmlglobal.isObject()); - - QV4::ExecutionEngine *v4 = qmlglobal.asObject()->engine(); - Scope scope(v4); - QV4::Scoped<QmlContextWrapper> c(scope, qmlglobal); - Q_ASSERT(c); - c->d()->ownsContext = true; -} - -ReturnedValue QmlContextWrapper::get(Managed *m, String *name, bool *hasProperty) +ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<QmlContextWrapper>()); - QmlContextWrapper *resource = static_cast<QmlContextWrapper *>(m); + const QmlContextWrapper *resource = static_cast<const QmlContextWrapper *>(m); QV4::ExecutionEngine *v4 = resource->engine(); QV4::Scope scope(v4); // In V8 the JS global object would come _before_ the QML global object, // so simulate that here. bool hasProp; - QV4::ScopedValue result(scope, v4->globalObject()->get(name, &hasProp)); + QV4::ScopedValue result(scope, v4->globalObject->get(name, &hasProp)); if (hasProp) { if (hasProperty) *hasProperty = hasProp; @@ -145,7 +126,7 @@ ReturnedValue QmlContextWrapper::get(Managed *m, String *name, bool *hasProperty if (resource->d()->isNullWrapper) return Object::get(m, name, hasProperty); - if (QV4::QmlContextWrapper::callingContext(v4) != resource->d()->context) + if (v4->callingQmlContext() != resource->d()->context) return Object::get(m, name, hasProperty); result = Object::get(m, name, &hasProp); @@ -209,7 +190,8 @@ ReturnedValue QmlContextWrapper::get(Managed *m, String *name, bool *hasProperty if (propertyIdx < context->idValueCount) { - ep->captureProperty(&context->idValues[propertyIdx].bindings); + if (ep->propertyCapture) + ep->propertyCapture->captureProperty(&context->idValues[propertyIdx].bindings); if (hasProperty) *hasProperty = true; return QV4::QObjectWrapper::wrap(v4, context->idValues[propertyIdx]); @@ -217,8 +199,8 @@ ReturnedValue QmlContextWrapper::get(Managed *m, String *name, bool *hasProperty QQmlContextPrivate *cp = context->asQQmlContextPrivate(); - ep->captureProperty(context->asQQmlContext(), -1, - propertyIdx + cp->notifyIndex); + if (ep->propertyCapture) + ep->propertyCapture->captureProperty(context->asQQmlContext(), -1, propertyIdx + cp->notifyIndex); const QVariant &value = cp->propertyValues.at(propertyIdx); if (hasProperty) @@ -278,10 +260,9 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value) return; QV4::Scoped<QmlContextWrapper> wrapper(scope, resource); - PropertyAttributes attrs; - Property *pd = wrapper->__getOwnProperty__(name, &attrs); - if (pd) { - wrapper->putValue(pd, attrs, value); + uint member = wrapper->internalClass()->find(name); + if (member < UINT_MAX) { + wrapper->putValue(wrapper->propertyAt(member), wrapper->internalClass()->propertyData[member], value); return; } @@ -342,14 +323,6 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value) Object::put(m, name, value); } -void QmlContextWrapper::markObjects(Heap::Base *m, ExecutionEngine *engine) -{ - QmlContextWrapper::Data *This = static_cast<QmlContextWrapper::Data *>(m); - if (This->idObjectsWrapper) - This->idObjectsWrapper->mark(engine); - Object::markObjects(m, engine); -} - void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const CompiledData::Function *compiledFunction) { // Let the caller check and avoid the function call :) @@ -358,13 +331,13 @@ void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const C QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0; if (!ep) return; - QQmlEnginePrivate::PropertyCapture *capture = ep->propertyCapture; + QQmlPropertyCapture *capture = ep->propertyCapture; if (!capture) return; QV4::Scope scope(engine); - QV4::Scoped<QmlContextWrapper> contextWrapper(scope, engine->qmlContextObject()); - QQmlContextData *qmlContext = contextWrapper->getContext(); + QV4::Scoped<QmlContext> context(scope, engine->qmlContext()); + QQmlContextData *qmlContext = context->qmlContext(); const quint32 *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable(); const int idObjectDependencyCount = compiledFunction->nDependingIdObjects; @@ -382,7 +355,7 @@ void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const C capture->captureProperty(qmlContext->contextObject, propertyIndex, notifyIndex); } - QObject *scopeObject = contextWrapper->getScopeObject(); + QObject *scopeObject = context->qmlScope(); const quint32 *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable(); const int scopePropertyDependencyCount = compiledFunction->nDependingScopeProperties; for (int i = 0; i < scopePropertyDependencyCount; ++i) { @@ -393,15 +366,6 @@ void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const C } -ReturnedValue QmlContextWrapper::idObjectsArray() -{ - if (!d()->idObjectsWrapper) { - ExecutionEngine *v4 = engine(); - d()->idObjectsWrapper = v4->memoryManager->alloc<QQmlIdObjectsArray>(v4, this); - } - return d()->idObjectsWrapper->asReturnedValue(); -} - ReturnedValue QmlContextWrapper::qmlSingletonWrapper(ExecutionEngine *v4, String *name) { if (!d()->context->imports) @@ -423,46 +387,4 @@ ReturnedValue QmlContextWrapper::qmlSingletonWrapper(ExecutionEngine *v4, String return QJSValuePrivate::convertedToValue(engine(), siinfo->scriptApi(e)); } -DEFINE_OBJECT_VTABLE(QQmlIdObjectsArray); - -Heap::QQmlIdObjectsArray::QQmlIdObjectsArray(ExecutionEngine *engine, QV4::QmlContextWrapper *contextWrapper) - : Heap::Object(engine) - , contextWrapper(contextWrapper->d()) -{ -} - -ReturnedValue QQmlIdObjectsArray::getIndexed(Managed *m, uint index, bool *hasProperty) -{ - Scope scope(static_cast<QV4::QQmlIdObjectsArray*>(m)->engine()); - Scoped<QQmlIdObjectsArray> This(scope, static_cast<QV4::QQmlIdObjectsArray*>(m)); - Scoped<QmlContextWrapper> contextWrapper(scope, This->d()->contextWrapper); - QQmlContextData *context = contextWrapper->getContext(); - if (!context) { - if (hasProperty) - *hasProperty = false; - return Encode::undefined(); - } - if (index >= (uint)context->idValueCount) { - if (hasProperty) - *hasProperty = false; - return Encode::undefined(); - } - - if (hasProperty) - *hasProperty = true; - - QQmlEnginePrivate *ep = scope.engine->qmlEngine() ? QQmlEnginePrivate::get(scope.engine->qmlEngine()) : 0; - if (ep) - ep->captureProperty(&context->idValues[index].bindings); - - return QObjectWrapper::wrap(This->engine(), context->idValues[index].data()); -} - -void QQmlIdObjectsArray::markObjects(Heap::Base *that, ExecutionEngine *engine) -{ - QQmlIdObjectsArray::Data *This = static_cast<QQmlIdObjectsArray::Data *>(that); - This->contextWrapper->mark(engine); - Object::markObjects(that, engine); -} - QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcontextwrapper_p.h b/src/qml/qml/qqmlcontextwrapper_p.h index 52d8677103..7b5d3216df 100644 --- a/src/qml/qml/qqmlcontextwrapper_p.h +++ b/src/qml/qml/qqmlcontextwrapper_p.h @@ -48,7 +48,7 @@ #include <QtCore/qglobal.h> #include <private/qtqmlglobal_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4object_p.h> #include <private/qqmlcontext_p.h> #include <private/qv4functionobject_p.h> @@ -65,8 +65,6 @@ struct QmlContextWrapper; namespace Heap { -struct QQmlIdObjectsArray; - struct QmlContextWrapper : Object { QmlContextWrapper(ExecutionEngine *engine, QQmlContextData *context, QObject *scopeObject, bool ownsContext = false); ~QmlContextWrapper(); @@ -76,12 +74,6 @@ struct QmlContextWrapper : Object { QQmlGuardedContextData context; QPointer<QObject> scopeObject; - QQmlIdObjectsArray *idObjectsWrapper; -}; - -struct QQmlIdObjectsArray : Object { - QQmlIdObjectsArray(QV4::ExecutionEngine *engine, QV4::QmlContextWrapper *contextWrapper); - QmlContextWrapper *contextWrapper; }; } @@ -94,8 +86,9 @@ struct Q_QML_EXPORT QmlContextWrapper : Object static ReturnedValue qmlScope(ExecutionEngine *e, QQmlContextData *ctxt, QObject *scope); static ReturnedValue urlScope(ExecutionEngine *v4, const QUrl &); - static QQmlContextData *callingContext(ExecutionEngine *v4); - static void takeContextOwnership(const Value &qmlglobal); + void takeContextOwnership() { + d()->ownsContext = true; + } inline QObject *getScopeObject() const { return d()->scopeObject; } inline QQmlContextData *getContext() const { return d()->context; } @@ -103,24 +96,12 @@ struct Q_QML_EXPORT QmlContextWrapper : Object void setReadOnly(bool b) { d()->readOnly = b; } - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); static void put(Managed *m, String *name, const Value &value); - static void markObjects(Heap::Base *m, ExecutionEngine *engine); static void registerQmlDependencies(ExecutionEngine *context, const CompiledData::Function *compiledFunction); - ReturnedValue idObjectsArray(); ReturnedValue qmlSingletonWrapper(ExecutionEngine *e, String *name); - -}; - -struct QQmlIdObjectsArray : public Object -{ - V4_OBJECT2(QQmlIdObjectsArray, Object) - - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); - static void markObjects(Heap::Base *that, ExecutionEngine *engine); - }; } diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h index 04c42b638d..3d2a76693a 100644 --- a/src/qml/qml/qqmldata_p.h +++ b/src/qml/qml/qqmldata_p.h @@ -48,8 +48,9 @@ #include <private/qtqmlglobal_p.h> #include <private/qobject_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4persistent_p.h> +#include <qjsengine.h> QT_BEGIN_NAMESPACE @@ -58,7 +59,7 @@ class QQmlEngine; class QQmlGuardImpl; class QQmlCompiledData; class QQmlAbstractBinding; -class QQmlAbstractBoundSignal; +class QQmlBoundSignal; class QQmlContext; class QQmlPropertyCache; class QQmlContextData; @@ -72,15 +73,7 @@ class QQmlNotifierEndpoint; class Q_QML_PRIVATE_EXPORT QQmlData : public QAbstractDeclarativeData { public: - QQmlData() - : ownedByQml1(false), ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false), - hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false), - hasVMEMetaObject(false), parentFrozen(false), bindingBitsSize(0), bindingBits(0), notifyList(0), context(0), outerContext(0), - bindings(0), signalHandlers(0), nextContextObject(0), prevContextObject(0), - lineNumber(0), columnNumber(0), jsEngineId(0), compiledData(0), deferredData(0), - propertyCache(0), guards(0), extendedData(0) { - init(); - } + QQmlData(); static inline void init() { static bool initialized = false; @@ -158,7 +151,7 @@ public: QQmlContextData *outerContext; QQmlAbstractBinding *bindings; - QQmlAbstractBoundSignal *signalHandlers; + QQmlBoundSignal *signalHandlers; // Linked list for QQmlContext::contextObjects QQmlData *nextContextObject; diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qml/qqmldirparser.cpp index 7f6310d58e..57b50733ea 100644 --- a/src/qml/qml/qqmldirparser.cpp +++ b/src/qml/qml/qqmldirparser.cpp @@ -146,7 +146,7 @@ bool QQmlDirParser::parse(const QString &source) if (invalidLine) { reportError(lineNumber, 0, - QString::fromLatin1("invalid qmldir directive contains too many tokens")); + QStringLiteral("invalid qmldir directive contains too many tokens")); continue; } else if (sectionCount == 0) { continue; // no sections, no party. @@ -154,17 +154,17 @@ bool QQmlDirParser::parse(const QString &source) } else if (sections[0] == QLatin1String("module")) { if (sectionCount != 2) { reportError(lineNumber, 0, - QString::fromLatin1("module identifier directive requires one argument, but %1 were provided").arg(sectionCount - 1)); + QStringLiteral("module identifier directive requires one argument, but %1 were provided").arg(sectionCount - 1)); continue; } if (!_typeNamespace.isEmpty()) { reportError(lineNumber, 0, - QString::fromLatin1("only one module identifier directive may be defined in a qmldir file")); + QStringLiteral("only one module identifier directive may be defined in a qmldir file")); continue; } if (!firstLine) { reportError(lineNumber, 0, - QString::fromLatin1("module identifier directive must be the first directive in a qmldir file")); + QStringLiteral("module identifier directive must be the first directive in a qmldir file")); continue; } @@ -173,7 +173,7 @@ bool QQmlDirParser::parse(const QString &source) } else if (sections[0] == QLatin1String("plugin")) { if (sectionCount < 2 || sectionCount > 3) { reportError(lineNumber, 0, - QString::fromLatin1("plugin directive requires one or two arguments, but %1 were provided").arg(sectionCount - 1)); + QStringLiteral("plugin directive requires one or two arguments, but %1 were provided").arg(sectionCount - 1)); continue; } @@ -185,7 +185,7 @@ bool QQmlDirParser::parse(const QString &source) } else if (sections[0] == QLatin1String("internal")) { if (sectionCount != 3) { reportError(lineNumber, 0, - QString::fromLatin1("internal types require 2 arguments, but %1 were provided").arg(sectionCount - 1)); + QStringLiteral("internal types require 2 arguments, but %1 were provided").arg(sectionCount - 1)); continue; } Component entry(sections[1], sections[2], -1, -1); @@ -194,7 +194,7 @@ bool QQmlDirParser::parse(const QString &source) } else if (sections[0] == QLatin1String("singleton")) { if (sectionCount < 3 || sectionCount > 4) { reportError(lineNumber, 0, - QString::fromLatin1("singleton types require 2 or 3 arguments, but %1 were provided").arg(sectionCount - 1)); + QStringLiteral("singleton types require 2 or 3 arguments, but %1 were provided").arg(sectionCount - 1)); continue; } else if (sectionCount == 3) { // handle qmldir directory listing case where singleton is defined in the following pattern: @@ -218,7 +218,7 @@ bool QQmlDirParser::parse(const QString &source) } else if (sections[0] == QLatin1String("typeinfo")) { if (sectionCount != 2) { reportError(lineNumber, 0, - QString::fromLatin1("typeinfo requires 1 argument, but %1 were provided").arg(sectionCount - 1)); + QStringLiteral("typeinfo requires 1 argument, but %1 were provided").arg(sectionCount - 1)); continue; } #ifdef QT_CREATOR @@ -228,13 +228,13 @@ bool QQmlDirParser::parse(const QString &source) } else if (sections[0] == QLatin1String("designersupported")) { if (sectionCount != 1) - reportError(lineNumber, 0, QString::fromLatin1("designersupported does not expect any argument")); + reportError(lineNumber, 0, QStringLiteral("designersupported does not expect any argument")); else _designerSupported = true; } else if (sections[0] == QLatin1String("depends")) { if (sectionCount != 3) { reportError(lineNumber, 0, - QString::fromLatin1("depends requires 2 arguments, but %1 were provided").arg(sectionCount - 1)); + QStringLiteral("depends requires 2 arguments, but %1 were provided").arg(sectionCount - 1)); continue; } @@ -268,7 +268,7 @@ bool QQmlDirParser::parse(const QString &source) } } else { reportError(lineNumber, 0, - QString::fromLatin1("a component declaration requires two or three arguments, but %1 were provided").arg(sectionCount)); + QStringLiteral("a component declaration requires two or three arguments, but %1 were provided").arg(sectionCount)); } firstLine = false; @@ -304,7 +304,9 @@ QList<QQmlError> QQmlDirParser::errors(const QString &uri) const { QUrl url(uri); QList<QQmlError> errors; - for (int i = 0; i < _errors.size(); ++i) { + const int numErrors = _errors.size(); + errors.reserve(numErrors); + for (int i = 0; i < numErrors; ++i) { const QQmlJS::DiagnosticMessage &msg = _errors.at(i); QQmlError e; QString description = msg.message; @@ -362,14 +364,14 @@ bool QQmlDirParser::designerSupported() const QDebug &operator<< (QDebug &debug, const QQmlDirParser::Component &component) { - const QString output = QString::fromLatin1("{%1 %2.%3}"). + const QString output = QStringLiteral("{%1 %2.%3}"). arg(component.typeName).arg(component.majorVersion).arg(component.minorVersion); return debug << qPrintable(output); } QDebug &operator<< (QDebug &debug, const QQmlDirParser::Script &script) { - const QString output = QString::fromLatin1("{%1 %2.%3}"). + const QString output = QStringLiteral("{%1 %2.%3}"). arg(script.nameSpace).arg(script.majorVersion).arg(script.minorVersion); return debug << qPrintable(output); } diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index ffc890a2cf..9c5e48ae32 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -42,7 +42,6 @@ #include "qqmlexpression.h" #include "qqmlcomponent.h" #include "qqmlvme_p.h" -#include <private/qqmlenginedebugservice_p.h> #include "qqmlstringconverters_p.h" #include "qqmlxmlhttprequest_p.h" #include "qqmlscriptstring.h" @@ -54,11 +53,7 @@ #include "qqmllist_p.h" #include "qqmltypenamecache_p.h" #include "qqmlnotifier_p.h" -#include <private/qqmldebugserver_p.h> -#include <private/qqmlprofilerservice_p.h> -#include <private/qv4debugservice_p.h> -#include <private/qdebugmessageservice_p.h> -#include <private/qqmlenginecontrolservice_p.h> +#include <private/qqmldebugconnector_p.h> #include "qqmlincubator.h" #include "qqmlabstracturlinterceptor.h" #include <private/qqmlboundsignal_p.h> @@ -225,7 +220,6 @@ void QQmlEnginePrivate::activateDesignerMode() /*! \class QQmlImageProviderBase \brief The QQmlImageProviderBase class is used to register image providers in the QML engine. - \mainclass \inmodule QtQml Image providers must be registered with the QML engine. The only information the QML @@ -247,6 +241,10 @@ void QQmlEnginePrivate::activateDesignerMode() The QQuickImageProvider::requestPixmap() method will be called for all image requests. \value Texture The Image Provider provides QSGTextureProvider based images. The QQuickImageProvider::requestTexture() method will be called for all image requests. + \value ImageResponse The Image provider provides QQuickTextureFactory based images. + Should only be used in QQuickAsyncImageProvider or its subclasses. + The QQuickAsyncImageProvider::requestImageResponse() method will be called for all image requests. + Since Qt 5.6 \omitvalue Invalid */ @@ -594,7 +592,7 @@ the same object as is returned from the Qt.include() call. // Qt.include() is implemented in qv4include.cpp QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e) -: propertyCapture(0), rootContext(0), isDebugging(false), +: propertyCapture(0), rootContext(0), profiler(0), outputWarningsToMsgLog(true), cleanup(0), erroredBindings(0), inProgressCreations(0), workerScriptEngine(0), @@ -607,8 +605,8 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e) QQmlEnginePrivate::~QQmlEnginePrivate() { - typedef QHash<QPair<QQmlType *, int>, QQmlPropertyCache *>::Iterator TypePropertyCacheIt; - typedef QHash<int, QQmlCompiledData *>::Iterator CompositeTypesIt; + typedef QHash<QPair<QQmlType *, int>, QQmlPropertyCache *>::const_iterator TypePropertyCacheIt; + typedef QHash<int, QQmlCompiledData *>::const_iterator CompositeTypesIt; if (inProgressCreations) qWarning() << QQmlEngine::tr("There are still \"%1\" items in the process of being created at engine destruction.").arg(inProgressCreations); @@ -627,9 +625,9 @@ QQmlEnginePrivate::~QQmlEnginePrivate() if (incubationController) incubationController->d = 0; incubationController = 0; - for (TypePropertyCacheIt iter = typePropertyCache.begin(), end = typePropertyCache.end(); iter != end; ++iter) + for (TypePropertyCacheIt iter = typePropertyCache.cbegin(), end = typePropertyCache.cend(); iter != end; ++iter) (*iter)->release(); - for (CompositeTypesIt iter = m_compositeTypes.begin(), end = m_compositeTypes.end(); iter != end; ++iter) { + for (CompositeTypesIt iter = m_compositeTypes.cbegin(), end = m_compositeTypes.cend(); iter != end; ++iter) { iter.value()->isRegisteredWithEngine = false; // since unregisterInternalCompositeType() will not be called in this @@ -666,6 +664,17 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o) } } +QQmlData::QQmlData() + : ownedByQml1(false), ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false), + hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false), + hasVMEMetaObject(false), parentFrozen(false), bindingBitsSize(0), bindingBits(0), notifyList(0), context(0), outerContext(0), + bindings(0), signalHandlers(0), nextContextObject(0), prevContextObject(0), + lineNumber(0), columnNumber(0), jsEngineId(0), compiledData(0), deferredData(0), + propertyCache(0), guards(0), extendedData(0) +{ + init(); +} + void QQmlData::destroyed(QAbstractDeclarativeData *d, QObject *o) { QQmlData *ddata = static_cast<QQmlData *>(d); @@ -799,7 +808,7 @@ void QQmlData::markAsDeleted(QObject *o) QQmlData::setQueuedForDeletion(o); QObjectPrivate *p = QObjectPrivate::get(o); - for (QList<QObject *>::iterator it = p->children.begin(), end = p->children.end(); it != end; ++it) { + for (QList<QObject *>::const_iterator it = p->children.constBegin(), end = p->children.constEnd(); it != end; ++it) { QQmlData::markAsDeleted(*it); } } @@ -824,14 +833,12 @@ void QQmlData::flushPendingBindingImpl(int coreIndex) // Find the binding QQmlAbstractBinding *b = bindings; - while (b && *b->m_mePtr && b->propertyIndex() != coreIndex) + while (b && b->targetPropertyIndex() != coreIndex) b = b->nextBinding(); - if (b && b->propertyIndex() == coreIndex) { - b->clear(); + if (b && b->targetPropertyIndex() == coreIndex) b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); - } } bool QQmlEnginePrivate::baseModulesUninitialized = true; @@ -861,15 +868,9 @@ void QQmlEnginePrivate::init() rootContext = new QQmlContext(q,true); - if (QCoreApplication::instance()->thread() == q->thread() && - QQmlEngineDebugService::isDebuggingEnabled()) { - isDebugging = true; - QQmlEngineDebugService::instance(); - QV4DebugService::instance(); - QQmlProfilerService::instance(); - QDebugMessageService::instance(); - QQmlEngineControlService::instance(); - QQmlDebugServer::instance()->addEngine(q); + if (QCoreApplication::instance()->thread() == q->thread() && QQmlDebugConnector::instance()) { + QQmlDebugConnector::instance()->open(); + QQmlDebugConnector::instance()->addEngine(q); } } @@ -886,7 +887,6 @@ QQuickWorkerScriptEngine *QQmlEnginePrivate::getWorkerScriptEngine() \since 5.0 \inmodule QtQml \brief The QQmlEngine class provides an environment for instantiating QML components. - \mainclass Each QML component is instantiated in a QQmlContext. QQmlContext's are essential for passing data to QML @@ -947,8 +947,9 @@ QQmlEngine::QQmlEngine(QQmlEnginePrivate &dd, QObject *parent) QQmlEngine::~QQmlEngine() { Q_D(QQmlEngine); - if (d->isDebugging) - QQmlDebugServer::instance()->removeEngine(this); + QQmlDebugConnector *server = QQmlDebugConnector::instance(); + if (server) + server->removeEngine(this); d->typeLoader.invalidate(); @@ -1492,51 +1493,6 @@ Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *o #endif // QT_DEPRECATED_SINCE(5, 1) -QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning) -{ -#ifndef QQML_NO_DEBUG_PROTOCOL - if (!QQmlEnginePrivate::qml_debugging_enabled - && printWarning) { - qDebug("QML debugging is enabled. Only use this in a safe environment."); - } - QQmlEnginePrivate::qml_debugging_enabled = true; -#else - Q_UNUSED(printWarning); -#endif -} - -/*! - * \enum QQmlDebuggingEnabler::StartMode - * - * Defines the debug server's start behavior. You can interrupt QML engines starting while a debug - * client is connecting, in order to set breakpoints in or profile startup code. - * - * \value DoNotWaitForClient Run any QML engines as usual while the debug services are connecting. - * \value WaitForClient If a QML engine starts while the debug services are connecting, - * interrupt it until they are done. - */ - -/*! - * Enables debugging for QML engines created after calling this function. The debug server will - * listen on \a port at \a hostName and block the QML engine until it receives a connection if - * \a mode is \c WaitForClient. If \a mode is not specified it won't block and if \a hostName is not - * specified it will listen on all available interfaces. You can only start one debug server at a - * time. A debug server may have already been started if the -qmljsdebugger= command line argument - * was given. This method returns \c true if a new debug server was successfully started, or - * \c false otherwise. - */ -bool QQmlDebuggingEnabler::startTcpDebugServer(int port, StartMode mode, const QString &hostName) -{ -#ifndef QQML_NO_DEBUG_PROTOCOL - return QQmlDebugServer::enable(port, port, mode == WaitForClient, hostName); -#else - Q_UNUSED(port); - Q_UNUSED(block); - Q_UNUSED(hostName); - return false; -#endif -} - class QQmlDataExtended { public: QQmlDataExtended(); @@ -1678,12 +1634,11 @@ void QQmlData::destroyed(QObject *object) QQmlAbstractBinding *binding = bindings; while (binding) { - QQmlAbstractBinding *next = binding->nextBinding(); binding->setAddedToObject(false); - binding->setNextBinding(0); - binding->destroy(); - binding = next; + binding = binding->nextBinding(); } + if (bindings && !bindings->ref.deref()) + delete bindings; if (compiledData) { compiledData->release(); @@ -1696,9 +1651,9 @@ void QQmlData::destroyed(QObject *object) deferredData = 0; } - QQmlAbstractBoundSignal *signalHandler = signalHandlers; + QQmlBoundSignal *signalHandler = signalHandlers; while (signalHandler) { - if (signalHandler->isEvaluating()) { + if (signalHandler->isNotifying()) { // The object is being deleted during signal handler evaluation. // This will cause a crash due to invalid memory access when the // evaluation has completed. @@ -1710,7 +1665,7 @@ void QQmlData::destroyed(QObject *object) if (location.sourceFile.isEmpty()) location.sourceFile = QStringLiteral("<Unknown File>"); locationString.append(location.sourceFile); - locationString.append(QString::fromLatin1(":%0: ").arg(location.line)); + locationString.append(QStringLiteral(":%0: ").arg(location.line)); QString source = expr->expression(); if (source.size() > 100) { source.truncate(96); @@ -1727,7 +1682,7 @@ void QQmlData::destroyed(QObject *object) "%s", object, qPrintable(locationString)); } - QQmlAbstractBoundSignal *next = signalHandler->m_nextSignal; + QQmlBoundSignal *next = signalHandler->m_nextSignal; signalHandler->m_prevSignal = 0; signalHandler->m_nextSignal = 0; delete signalHandler; @@ -2140,8 +2095,7 @@ QString QQmlEngine::offlineStoragePath() const return d->offlineStoragePath; } -QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersion, - QQmlError &error) +QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersion) { QList<QQmlType *> types; @@ -2203,10 +2157,10 @@ QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersi // Properties override: // * other elements of the same name +#if 0 bool overloadError = false; QString overloadName; -#if 0 for (QQmlPropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin(); !overloadError && iter != raw->stringCache.end(); ++iter) { @@ -2223,7 +2177,6 @@ QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersi overloadError = true; } } -#endif if (overloadError) { if (hasCopied) raw->release(); @@ -2231,6 +2184,7 @@ QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersi error.setDescription(QLatin1String("Type ") + type->qmlTypeName() + QLatin1Char(' ') + QString::number(type->majorVersion()) + QLatin1Char('.') + QString::number(minorVersion) + QLatin1String(" contains an illegal property \"") + overloadName + QLatin1String("\". This is an error in the type's implementation.")); return 0; } +#endif if (!hasCopied) raw->addref(); typePropertyCache.insert(qMakePair(type, minorVersion), raw); @@ -2281,8 +2235,8 @@ bool QQmlEnginePrivate::isList(int t) const int QQmlEnginePrivate::listType(int t) const { Locker locker(this); - QHash<int, int>::ConstIterator iter = m_qmlLists.find(t); - if (iter != m_qmlLists.end()) + QHash<int, int>::ConstIterator iter = m_qmlLists.constFind(t); + if (iter != m_qmlLists.cend()) return *iter; else return QQmlMetaType::listType(t); @@ -2291,8 +2245,8 @@ int QQmlEnginePrivate::listType(int t) const QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const { Locker locker(this); - QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.find(t); - if (iter != m_compositeTypes.end()) { + QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.constFind(t); + if (iter != m_compositeTypes.cend()) { return QQmlMetaObject((*iter)->rootPropertyCache); } else { QQmlType *type = QQmlMetaType::qmlType(t); @@ -2303,8 +2257,8 @@ QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const { Locker locker(this); - QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.find(t); - if (iter != m_compositeTypes.end()) { + QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.constFind(t); + if (iter != m_compositeTypes.cend()) { return QQmlMetaObject((*iter)->rootPropertyCache); } else { QQmlType *type = QQmlMetaType::qmlType(t); @@ -2315,8 +2269,8 @@ QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t) { Locker locker(this); - QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t); - if (iter != m_compositeTypes.end()) { + QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.constFind(t); + if (iter != m_compositeTypes.cend()) { return (*iter)->rootPropertyCache; } else { QQmlType *type = QQmlMetaType::qmlType(t); @@ -2328,8 +2282,8 @@ QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t) QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t) { Locker locker(this); - QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t); - if (iter != m_compositeTypes.end()) { + QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.constFind(t); + if (iter != m_compositeTypes.cend()) { return (*iter)->rootPropertyCache; } else { QQmlType *type = QQmlMetaType::qmlType(t); diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h index df673c1fd5..61a884279d 100644 --- a/src/qml/qml/qqmlengine.h +++ b/src/qml/qml/qqmlengine.h @@ -52,7 +52,9 @@ public: Image, Pixmap, Texture, - Invalid + Invalid, + ImageResponse + // ### Qt6: reorder these, and give Invalid a fixed large value }; enum Flag { diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index f1fbad3cf8..26ee3bd655 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -85,7 +85,6 @@ class QQmlImportDatabase; class QNetworkReply; class QNetworkAccessManager; class QQmlNetworkAccessManagerFactory; -class QQmlAbstractBinding; class QQmlTypeNameCache; class QQmlComponentAttached; class QQmlCleanup; @@ -95,6 +94,7 @@ class QQmlObjectCreator; class QDir; class QQmlIncubator; class QQmlProfiler; +class QQmlPropertyCapture; // This needs to be declared here so that the pool for it can live in QQmlEnginePrivate. // The inline method definitions are in qqmljavascriptexpression_p.h @@ -123,21 +123,11 @@ public: // is just qmlClearTypeRegistrations (which can't be called while an engine exists) static bool baseModulesUninitialized; - class PropertyCapture { - public: - inline virtual ~PropertyCapture() {} - virtual void captureProperty(QQmlNotifier *) = 0; - virtual void captureProperty(QObject *, int, int) = 0; - }; - - PropertyCapture *propertyCapture; - inline void captureProperty(QQmlNotifier *); - inline void captureProperty(QObject *, int, int); + QQmlPropertyCapture *propertyCapture; QRecyclePool<QQmlJavaScriptExpressionGuard> jsExpressionGuardPool; QQmlContext *rootContext; - bool isDebugging; QQmlProfiler *profiler; void enableProfiler(); @@ -208,7 +198,7 @@ public: inline static void deleteInEngineThread(QQmlEngine *, T *); // These methods may be called from the loader thread - inline QQmlPropertyCache *cache(QQmlType *, int, QQmlError &error); + inline QQmlPropertyCache *cache(QQmlType *, int); using QJSEnginePrivate::cache; // These methods may be called from the loader thread @@ -262,7 +252,7 @@ public: private: // Must be called locked - QQmlPropertyCache *createCache(QQmlType *, int, QQmlError &error); + QQmlPropertyCache *createCache(QQmlType *, int); // These members must be protected by a QQmlEnginePrivate::Locker as they are required by // the threaded loader. Only access them through their respective accessor methods. @@ -346,7 +336,7 @@ Returns a QQmlPropertyCache for \a type with \a minorVersion. The returned cache is not referenced, so if it is to be stored, call addref(). */ -QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion, QQmlError &error) +QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion) { Q_ASSERT(type); @@ -355,7 +345,7 @@ QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion, QQ Locker locker(this); QQmlPropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion)); - if (!rv) rv = createCache(type, minorVersion, error); + if (!rv) rv = createCache(type, minorVersion); return rv; } @@ -414,18 +404,6 @@ QQmlEnginePrivate *QQmlEnginePrivate::get(QV4::ExecutionEngine *e) return get(qmlEngine); } -void QQmlEnginePrivate::captureProperty(QQmlNotifier *n) -{ - if (propertyCapture) - propertyCapture->captureProperty(n); -} - -void QQmlEnginePrivate::captureProperty(QObject *o, int c, int n) -{ - if (propertyCapture) - propertyCapture->captureProperty(o, c, n); -} - void QQmlEnginePrivate::setDebugChangesCache(const QHash<QUrl, QByteArray> &changes) { Locker locker(this); diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp index 35e0bc8c64..332b99ee8f 100644 --- a/src/qml/qml/qqmlexpression.cpp +++ b/src/qml/qml/qqmlexpression.cpp @@ -45,13 +45,8 @@ QT_BEGIN_NAMESPACE -static QQmlJavaScriptExpression::VTable QQmlExpressionPrivate_jsvtable = { - QQmlExpressionPrivate::expressionIdentifier, - QQmlExpressionPrivate::expressionChanged -}; - QQmlExpressionPrivate::QQmlExpressionPrivate() -: QQmlJavaScriptExpression(&QQmlExpressionPrivate_jsvtable), +: QQmlJavaScriptExpression(), expressionFunctionValid(true), line(0), column(0) { @@ -65,7 +60,7 @@ void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr, QOb { expression = expr; - QQmlAbstractExpression::setContext(ctxt); + QQmlJavaScriptExpression::setContext(ctxt); setScopeObject(me); expressionFunctionValid = false; } @@ -74,9 +69,9 @@ void QQmlExpressionPrivate::init(QQmlContextData *ctxt, QV4::Function *runtimeFu { expressionFunctionValid = true; QV4::ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(ctxt->engine); - function.set(engine, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxt, me, runtimeFunction)); + m_function.set(engine, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxt, me, runtimeFunction)); - QQmlAbstractExpression::setContext(ctxt); + QQmlJavaScriptExpression::setContext(ctxt); setScopeObject(me); } @@ -246,18 +241,12 @@ void QQmlExpression::setExpression(const QString &expression) // Must be called with a valid handle scope QV4::ReturnedValue QQmlExpressionPrivate::v4value(bool *isUndefined) { - Q_Q(QQmlExpression); - - QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(q->engine())->v4engine(); - if (!expressionFunctionValid) { - function.set(v4, qmlBinding(context(), scopeObject(), expression, url, line, &qmlscope)); + createQmlBinding(context(), scopeObject(), expression, url, line); expressionFunctionValid = true; } - QV4::Scope scope(v4); - QV4::ScopedValue f(scope, function.value()); - return evaluate(context(), f, isUndefined); + return evaluate(isUndefined); } QVariant QQmlExpressionPrivate::value(bool *isUndefined) @@ -432,22 +421,15 @@ QQmlError QQmlExpression::error() const calling QQmlExpression::evaluate()) before this signal will be emitted. */ -void QQmlExpressionPrivate::expressionChanged(QQmlJavaScriptExpression *e) -{ - QQmlExpressionPrivate *This = static_cast<QQmlExpressionPrivate *>(e); - This->expressionChanged(); -} - void QQmlExpressionPrivate::expressionChanged() { Q_Q(QQmlExpression); emit q->valueChanged(); } -QString QQmlExpressionPrivate::expressionIdentifier(QQmlJavaScriptExpression *e) +QString QQmlExpressionPrivate::expressionIdentifier() { - QQmlExpressionPrivate *This = static_cast<QQmlExpressionPrivate *>(e); - return QLatin1Char('"') + This->expression + QLatin1Char('"'); + return QLatin1Char('"') + expression + QLatin1Char('"'); } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlexpression_p.h b/src/qml/qml/qqmlexpression_p.h index d8da387878..2303539194 100644 --- a/src/qml/qml/qqmlexpression_p.h +++ b/src/qml/qml/qqmlexpression_p.h @@ -52,7 +52,6 @@ #include <private/qflagpointer_p.h> #include <private/qdeletewatcher_p.h> #include <private/qpointervaluepair_p.h> -#include <private/qqmlabstractexpression_p.h> #include <private/qqmljavascriptexpression_p.h> QT_BEGIN_NAMESPACE @@ -60,8 +59,7 @@ QT_BEGIN_NAMESPACE class QQmlExpression; class QString; class QQmlExpressionPrivate : public QObjectPrivate, - public QQmlJavaScriptExpression, - public QQmlAbstractExpression + public QQmlJavaScriptExpression { Q_DECLARE_PUBLIC(QQmlExpression) public: @@ -82,16 +80,12 @@ public: bool expressionFunctionValid:1; - // "Inherited" from QQmlJavaScriptExpression - static QString expressionIdentifier(QQmlJavaScriptExpression *); - static void expressionChanged(QQmlJavaScriptExpression *); + // Inherited from QQmlJavaScriptExpression + virtual QString expressionIdentifier(); virtual void expressionChanged(); QString expression; - QV4::PersistentValue qmlscope; - QV4::PersistentValue function; - QString url; // This is a QString for a reason. QUrls are slooooooow... quint16 line; quint16 column; diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp index d904242f93..0a2f4079c2 100644 --- a/src/qml/qml/qqmlglobal.cpp +++ b/src/qml/qml/qqmlglobal.cpp @@ -359,7 +359,7 @@ QObject *QQmlGuiProvider::inputMethod() { // We don't have any input method code by default QObject *o = new QObject(); - o->setObjectName(QString::fromLatin1("No inputMethod available")); + o->setObjectName(QStringLiteral("No inputMethod available")); QQmlEngine::setObjectOwnership(o, QQmlEngine::JavaScriptOwnership); return o; } @@ -368,7 +368,7 @@ QObject *QQmlGuiProvider::inputMethod() QObject *QQmlGuiProvider::styleHints() { QObject *o = new QObject(); - o->setObjectName(QString::fromLatin1("No styleHints available")); + o->setObjectName(QStringLiteral("No styleHints available")); QQmlEngine::setObjectOwnership(o, QQmlEngine::JavaScriptOwnership); return o; } diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index ff48a10d95..b17bb0455d 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -169,6 +169,7 @@ QQmlType *getTypeForUrl(const QString &urlString, const QHashedStringRef& typeNa } // namespace +#ifndef QT_NO_LIBRARY struct RegisteredPlugin { QString uri; QPluginLoader* loader; @@ -193,6 +194,7 @@ void qmlClearEnginePlugins() } typedef QPair<QStaticPlugin, QJsonArray> StaticPluginPair; +#endif class QQmlImportNamespace { @@ -292,9 +294,10 @@ public: const QString &uri, const QString &url, int vmaj, int vmin, QV4::CompiledData::Import::ImportType type, QList<QQmlError> *errors, bool lowPrecedence = false); - +#ifndef QT_NO_LIBRARY bool populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, const QString &qmldirPath, QList<QQmlError> *errors); +#endif }; /*! @@ -382,7 +385,7 @@ void QQmlImports::populateCache(QQmlTypeNameCache *cache) const // We need to exclude the entry for the current baseUrl. This can happen for example // when handling qmldir files on the remote dir case and the current type is marked as // singleton. -bool excludeBaseUrl(const QString &importUrl, const QString &fileName, const QString baseUrl) +bool excludeBaseUrl(const QString &importUrl, const QString &fileName, const QString &baseUrl) { if (importUrl.isEmpty()) return false; @@ -398,7 +401,7 @@ bool excludeBaseUrl(const QString &importUrl, const QString &fileName, const QSt return true; } -void findCompositeSingletons(const QQmlImportNamespace &set, QList<QQmlImports::CompositeSingletonReference> &resultList, QUrl baseUrl) +void findCompositeSingletons(const QQmlImportNamespace &set, QList<QQmlImports::CompositeSingletonReference> &resultList, const QUrl &baseUrl) { typedef QQmlDirComponents::const_iterator ConstIterator; @@ -826,6 +829,7 @@ QQmlImportNamespace *QQmlImportsPrivate::findQualifiedNamespace(const QHashedStr } +#ifndef QT_NO_LIBRARY /*! Get all static plugins that are QML plugins and has a meta data URI that begins with \a uri. Note that if e.g uri == "a", and different plugins have meta data "a", "a.2.1", "a.b.c", all @@ -869,6 +873,7 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res } return true; } +#endif /*! Import an extension defined by a qmldir file. @@ -995,6 +1000,13 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, } #else + Q_UNUSED(qmldirFilePath); + Q_UNUSED(uri); + Q_UNUSED(vmaj); + Q_UNUSED(vmin); + Q_UNUSED(database); + Q_UNUSED(qmldir); + Q_UNUSED(errors); return false; #endif // QT_NO_LIBRARY return true; @@ -1931,6 +1943,12 @@ bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &ba return true; #else + Q_UNUSED(instance); + Q_UNUSED(basePath); + Q_UNUSED(uri); + Q_UNUSED(typeNamespace); + Q_UNUSED(vmaj); + Q_UNUSED(errors); return false; #endif } @@ -2011,6 +2029,11 @@ bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QStr return true; #else + Q_UNUSED(filePath); + Q_UNUSED(uri); + Q_UNUSED(typeNamespace); + Q_UNUSED(vmaj); + Q_UNUSED(errors); return false; #endif } diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 02bd1c4b83..5f30eac066 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -35,7 +35,7 @@ #include <private/qqmlexpression_p.h> #include <private/qqmlcontextwrapper_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4functionobject_p.h> #include <private/qv4script_p.h> #include <private/qv4errorobject_p.h> @@ -83,13 +83,22 @@ void QQmlDelayedError::catchJavaScriptException(QV4::ExecutionEngine *engine) } -QQmlJavaScriptExpression::QQmlJavaScriptExpression(VTable *v) -: m_vtable(v) +QQmlJavaScriptExpression::QQmlJavaScriptExpression() + : m_error(0), + m_context(0), + m_prevExpression(0), + m_nextExpression(0) { } QQmlJavaScriptExpression::~QQmlJavaScriptExpression() { + if (m_prevExpression) { + *m_prevExpression = m_nextExpression; + if (m_nextExpression) + m_nextExpression->m_prevExpression = m_prevExpression; + } + clearGuards(); if (m_scopeObject.isT2()) // notify DeleteWatcher of our deletion. m_scopeObject.asT2()->_s = 0; @@ -106,40 +115,62 @@ void QQmlJavaScriptExpression::resetNotifyOnValueChanged() clearGuards(); } -QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context, - const QV4::Value &function, bool *isUndefined) +void QQmlJavaScriptExpression::setContext(QQmlContextData *context) { - QV4::ExecutionEngine *v4 = QV8Engine::getV4(context->engine); + if (m_prevExpression) { + *m_prevExpression = m_nextExpression; + if (m_nextExpression) + m_nextExpression->m_prevExpression = m_prevExpression; + m_prevExpression = 0; + m_nextExpression = 0; + } + + m_context = context; + + if (context) { + m_nextExpression = context->expressions; + if (m_nextExpression) + m_nextExpression->m_prevExpression = &m_nextExpression; + m_prevExpression = &context->expressions; + context->expressions = this; + } +} + +void QQmlJavaScriptExpression::refresh() +{ +} + +QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(bool *isUndefined) +{ + QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_context->engine); QV4::Scope scope(v4); QV4::ScopedCallData callData(scope); - return evaluate(context, function, callData, isUndefined); + return evaluate(callData, isUndefined); } -QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context, - const QV4::Value &function, - QV4::CallData *callData, - bool *isUndefined) +QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, bool *isUndefined) { - Q_ASSERT(context && context->engine); + Q_ASSERT(m_context && m_context->engine); - if (function.isUndefined()) { + QV4::Value *f = m_function.valueRef(); + if (!f || f->isUndefined()) { if (isUndefined) *isUndefined = true; return QV4::Encode::undefined(); } - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine); + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(m_context->engine); // All code that follows must check with watcher before it accesses data members // incase we have been deleted. DeleteWatcher watcher(this); Q_ASSERT(notifyOnValueChanged() || activeGuards.isEmpty()); - GuardCapture capture(context->engine, this, &watcher); + QQmlPropertyCapture capture(m_context->engine, this, &watcher); - QQmlEnginePrivate::PropertyCapture *lastPropertyCapture = ep->propertyCapture; - ep->propertyCapture = notifyOnValueChanged()?&capture:0; + QQmlPropertyCapture *lastPropertyCapture = ep->propertyCapture; + ep->propertyCapture = notifyOnValueChanged() ? &capture : 0; if (notifyOnValueChanged()) @@ -148,14 +179,14 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context, QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine()); QV4::Scope scope(v4); QV4::ScopedValue result(scope, QV4::Primitive::undefinedValue()); - callData->thisObject = v4->globalObject(); + callData->thisObject = v4->globalObject; if (scopeObject()) { QV4::ScopedValue value(scope, QV4::QObjectWrapper::wrap(v4, scopeObject())); if (value->isObject()) callData->thisObject = value; } - result = function.asFunctionObject()->call(callData); + result = f->as<QV4::FunctionObject>()->call(callData); if (scope.hasException()) { if (watcher.wasDeleted()) scope.engine->catchException(); // ignore exception @@ -178,7 +209,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context, capture.errorString = 0; } - while (Guard *g = capture.guards.takeFirst()) + while (QQmlJavaScriptExpressionGuard *g = capture.guards.takeFirst()) g->Delete(); ep->propertyCapture = lastPropertyCapture; @@ -186,7 +217,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context, return result->asReturnedValue(); } -void QQmlJavaScriptExpression::GuardCapture::captureProperty(QQmlNotifier *n) +void QQmlPropertyCapture::captureProperty(QQmlNotifier *n) { if (watcher->wasDeleted()) return; @@ -196,13 +227,13 @@ void QQmlJavaScriptExpression::GuardCapture::captureProperty(QQmlNotifier *n) while (!guards.isEmpty() && !guards.first()->isConnected(n)) guards.takeFirst()->Delete(); - Guard *g = 0; + QQmlJavaScriptExpressionGuard *g = 0; if (!guards.isEmpty()) { g = guards.takeFirst(); g->cancelNotify(); Q_ASSERT(g->isConnected(n)); } else { - g = Guard::New(expression, engine); + g = QQmlJavaScriptExpressionGuard::New(expression, engine); g->connect(n); } @@ -213,7 +244,7 @@ void QQmlJavaScriptExpression::GuardCapture::captureProperty(QQmlNotifier *n) \a n is in the signal index range (see QObjectPrivate::signalIndex()). */ -void QQmlJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, int n) +void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n) { if (watcher->wasDeleted()) return; @@ -223,7 +254,7 @@ void QQmlJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, if (!errorString) { errorString = new QStringList; QString preamble = QLatin1String("QQmlExpression: Expression ") + - expression->m_vtable->expressionIdentifier(expression) + + expression->expressionIdentifier() + QLatin1String(" depends on non-NOTIFYable properties:"); errorString->append(preamble); } @@ -242,13 +273,13 @@ void QQmlJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, while (!guards.isEmpty() && !guards.first()->isConnected(o, n)) guards.takeFirst()->Delete(); - Guard *g = 0; + QQmlJavaScriptExpressionGuard *g = 0; if (!guards.isEmpty()) { g = guards.takeFirst(); g->cancelNotify(); Q_ASSERT(g->isConnected(o, n)); } else { - g = Guard::New(expression, engine); + g = QQmlJavaScriptExpressionGuard::New(expression, engine); g->connect(o, n, engine); } @@ -258,31 +289,31 @@ void QQmlJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, void QQmlJavaScriptExpression::clearError() { - if (m_vtable.hasValue()) { - m_vtable.value().clearError(); - m_vtable.value().removeError(); - } + if (m_error) + delete m_error; + m_error = 0; } QQmlError QQmlJavaScriptExpression::error(QQmlEngine *engine) const { Q_UNUSED(engine); - if (m_vtable.hasValue()) - return m_vtable.constValue()->error(); + if (m_error) + return m_error->error(); else return QQmlError(); } QQmlDelayedError *QQmlJavaScriptExpression::delayedError() { - return &m_vtable.value(); + if (!m_error) + m_error = new QQmlDelayedError; + return m_error; } QV4::ReturnedValue QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scopeObject, - const QString &code, const QString &filename, quint16 line, - QV4::PersistentValue *qmlscope) + const QString &code, const QString &filename, quint16 line) { QQmlEngine *engine = ctxt->engine; QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); @@ -308,14 +339,11 @@ QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scopeObje ep->warning(error); return QV4::Encode::undefined(); } - if (qmlscope) - qmlscope->set(v4, qmlScopeObject); return result->asReturnedValue(); } -QV4::ReturnedValue QQmlJavaScriptExpression::qmlBinding(QQmlContextData *ctxt, QObject *qmlScope, - const QString &code, const QString &filename, quint16 line, - QV4::PersistentValue *qmlscope) +void QQmlJavaScriptExpression::createQmlBinding(QQmlContextData *ctxt, QObject *qmlScope, + const QString &code, const QString &filename, quint16 line) { QQmlEngine *engine = ctxt->engine; QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); @@ -339,17 +367,15 @@ QV4::ReturnedValue QQmlJavaScriptExpression::qmlBinding(QQmlContextData *ctxt, Q error.setUrl(QUrl::fromLocalFile(filename)); error.setObject(qmlScope); ep->warning(error); - return QV4::Encode::undefined(); + result = QV4::Encode::undefined(); } - if (qmlscope) - qmlscope->set(v4, qmlScopeObject); - return result->asReturnedValue(); + m_function.set(v4, result); } void QQmlJavaScriptExpression::clearGuards() { - while (Guard *g = activeGuards.takeFirst()) + while (QQmlJavaScriptExpressionGuard *g = activeGuards.takeFirst()) g->Delete(); } @@ -358,7 +384,7 @@ void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *e, void **) QQmlJavaScriptExpression *expression = static_cast<QQmlJavaScriptExpressionGuard *>(e)->expression; - expression->m_vtable->expressionChanged(expression); + expression->expressionChanged(); } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h index 989d5a0b0d..dfcf8b2d68 100644 --- a/src/qml/qml/qqmljavascriptexpression_p.h +++ b/src/qml/qml/qqmljavascriptexpression_p.h @@ -89,23 +89,17 @@ private: QQmlDelayedError **prevError; }; -class QQmlJavaScriptExpression +class Q_QML_PRIVATE_EXPORT QQmlJavaScriptExpression { public: - // Although this looks crazy, we implement our own "vtable" here, rather than relying on - // C++ virtuals, to save memory. By doing it ourselves, we can overload the storage - // location that is use for the vtable to also store the rarely used delayed error. - // If we use C++ virtuals, we can't do this and it consts us an extra sizeof(void *) in - // memory for every expression. - struct VTable { - QString (*expressionIdentifier)(QQmlJavaScriptExpression *); - void (*expressionChanged)(QQmlJavaScriptExpression *); - }; + QQmlJavaScriptExpression(); + virtual ~QQmlJavaScriptExpression(); - QQmlJavaScriptExpression(VTable *vtable); + virtual QString expressionIdentifier() = 0; + virtual void expressionChanged() = 0; - QV4::ReturnedValue evaluate(QQmlContextData *, const QV4::Value &function, bool *isUndefined); - QV4::ReturnedValue evaluate(QQmlContextData *, const QV4::Value &function, QV4::CallData *callData, bool *isUndefined); + QV4::ReturnedValue evaluate(bool *isUndefined); + QV4::ReturnedValue evaluate(QV4::CallData *callData, bool *isUndefined); inline bool notifyOnValueChanged() const; @@ -115,6 +109,13 @@ public: inline QObject *scopeObject() const; inline void setScopeObject(QObject *v); + bool isValid() const { return context() != 0; } + + QQmlContextData *context() const { return m_context; } + void setContext(QQmlContextData *context); + + virtual void refresh(); + class DeleteWatcher { public: inline DeleteWatcher(QQmlJavaScriptExpression *); @@ -136,46 +137,50 @@ public: static QV4::ReturnedValue evalFunction(QQmlContextData *ctxt, QObject *scope, const QString &code, const QString &filename, - quint16 line, - QV4::PersistentValue *qmlscope = 0); - // doesn't require rewriting the expression - static QV4::ReturnedValue qmlBinding(QQmlContextData *ctxt, QObject *scope, - const QString &code, - const QString &filename, quint16 line, - QV4::PersistentValue *qmlscope = 0); + quint16 line); protected: - ~QQmlJavaScriptExpression(); + void createQmlBinding(QQmlContextData *ctxt, QObject *scope, const QString &code, const QString &filename, quint16 line); private: - typedef QQmlJavaScriptExpressionGuard Guard; + friend class QQmlContextData; + friend class QQmlPropertyCapture; friend void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **); - struct GuardCapture : public QQmlEnginePrivate::PropertyCapture { - GuardCapture(QQmlEngine *engine, QQmlJavaScriptExpression *e, DeleteWatcher *w) - : engine(engine), expression(e), watcher(w), errorString(0) { } - - ~GuardCapture() { - Q_ASSERT(guards.isEmpty()); - Q_ASSERT(errorString == 0); - } - - virtual void captureProperty(QQmlNotifier *); - virtual void captureProperty(QObject *, int, int); - - QQmlEngine *engine; - QQmlJavaScriptExpression *expression; - DeleteWatcher *watcher; - QFieldList<Guard, &Guard::next> guards; - QStringList *errorString; - }; - - QPointerValuePair<VTable, QQmlDelayedError> m_vtable; + QQmlDelayedError *m_error; // We store some flag bits in the following flag pointers. // activeGuards:flag1 - notifyOnValueChanged // activeGuards:flag2 - useSharedContext QBiPointer<QObject, DeleteWatcher> m_scopeObject; - QForwardFieldList<Guard, &Guard::next> activeGuards; + QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> activeGuards; + + QQmlContextData *m_context; + QQmlJavaScriptExpression **m_prevExpression; + QQmlJavaScriptExpression *m_nextExpression; + +protected: + QV4::PersistentValue m_function; +}; + +class QQmlPropertyCapture +{ +public: + QQmlPropertyCapture(QQmlEngine *engine, QQmlJavaScriptExpression *e, QQmlJavaScriptExpression::DeleteWatcher *w) + : engine(engine), expression(e), watcher(w), errorString(0) { } + + ~QQmlPropertyCapture() { + Q_ASSERT(guards.isEmpty()); + Q_ASSERT(errorString == 0); + } + + void captureProperty(QQmlNotifier *); + void captureProperty(QObject *, int, int); + + QQmlEngine *engine; + QQmlJavaScriptExpression *expression; + QQmlJavaScriptExpression::DeleteWatcher *watcher; + QFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> guards; + QStringList *errorString; }; QQmlJavaScriptExpression::DeleteWatcher::DeleteWatcher(QQmlJavaScriptExpression *e) @@ -222,18 +227,18 @@ void QQmlJavaScriptExpression::setScopeObject(QObject *v) bool QQmlJavaScriptExpression::hasError() const { - return m_vtable.hasValue() && m_vtable.constValue()->isValid(); + return m_error && m_error->isValid(); } bool QQmlJavaScriptExpression::hasDelayedError() const { - return m_vtable.hasValue(); + return m_error; } QQmlJavaScriptExpressionGuard::QQmlJavaScriptExpressionGuard(QQmlJavaScriptExpression *e) -: expression(e), next(0) + : QQmlNotifierEndpoint(QQmlNotifierEndpoint::QQmlJavaScriptExpressionGuard), + expression(e), next(0) { - setCallback(QQmlNotifierEndpoint::QQmlJavaScriptExpressionGuard); } QQmlJavaScriptExpressionGuard * diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp index bcb1e72f0b..d09f4df54c 100644 --- a/src/qml/qml/qqmllistwrapper.cpp +++ b/src/qml/qml/qqmllistwrapper.cpp @@ -92,13 +92,13 @@ QVariant QmlListWrapper::toVariant() const } -ReturnedValue QmlListWrapper::get(Managed *m, String *name, bool *hasProperty) +ReturnedValue QmlListWrapper::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<QmlListWrapper>()); - QmlListWrapper *w = static_cast<QmlListWrapper *>(m); + const QmlListWrapper *w = static_cast<const QmlListWrapper *>(m); QV4::ExecutionEngine *v4 = w->engine(); - if (name->equals(v4->id_length) && !w->d()->object.isNull()) { + if (name->equals(v4->id_length()) && !w->d()->object.isNull()) { quint32 count = w->d()->property.count ? w->d()->property.count(&w->d()->property) : 0; return Primitive::fromUInt32(count).asReturnedValue(); } @@ -110,12 +110,12 @@ ReturnedValue QmlListWrapper::get(Managed *m, String *name, bool *hasProperty) return Object::get(m, name, hasProperty); } -ReturnedValue QmlListWrapper::getIndexed(Managed *m, uint index, bool *hasProperty) +ReturnedValue QmlListWrapper::getIndexed(const Managed *m, uint index, bool *hasProperty) { Q_UNUSED(hasProperty); Q_ASSERT(m->as<QmlListWrapper>()); - QmlListWrapper *w = static_cast<QmlListWrapper *>(m); + const QmlListWrapper *w = static_cast<const QmlListWrapper *>(m); QV4::ExecutionEngine *v4 = w->engine(); quint32 count = w->d()->property.count ? w->d()->property.count(&w->d()->property) : 0; @@ -138,9 +138,9 @@ void QmlListWrapper::put(Managed *m, String *name, const Value &value) Q_UNUSED(value); } -void QmlListWrapper::advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attrs) +void QmlListWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs) { - *name = (Heap::String *)0; + name->setM(0); *index = UINT_MAX; Q_ASSERT(m->as<QmlListWrapper>()); QmlListWrapper *w = static_cast<QmlListWrapper *>(m); diff --git a/src/qml/qml/qqmllistwrapper_p.h b/src/qml/qml/qqmllistwrapper_p.h index 3590bcb1c9..ff006d4302 100644 --- a/src/qml/qml/qqmllistwrapper_p.h +++ b/src/qml/qml/qqmllistwrapper_p.h @@ -50,7 +50,7 @@ #include <QtQml/qqmllist.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4object_p.h> QT_BEGIN_NAMESPACE @@ -81,10 +81,10 @@ struct Q_QML_EXPORT QmlListWrapper : Object QVariant toVariant() const; - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); + static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); static void put(Managed *m, String *name, const Value &value); - static void advanceIterator(Managed *m, ObjectIterator *it, Heap::String **name, uint *index, Property *p, PropertyAttributes *attributes); + static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); }; } diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp index 62b5b76ede..7f49798da6 100644 --- a/src/qml/qml/qqmllocale.cpp +++ b/src/qml/qml/qqmllocale.cpp @@ -65,13 +65,13 @@ static bool isLocaleObject(const QV4::Value &val) void QQmlDateExtension::registerExtension(QV4::ExecutionEngine *engine) { - engine->datePrototype.asObject()->defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString); - engine->datePrototype.asObject()->defineDefaultProperty(QStringLiteral("toLocaleTimeString"), method_toLocaleTimeString); - engine->datePrototype.asObject()->defineDefaultProperty(QStringLiteral("toLocaleDateString"), method_toLocaleDateString); - engine->dateCtor.objectValue()->defineDefaultProperty(QStringLiteral("fromLocaleString"), method_fromLocaleString); - engine->dateCtor.objectValue()->defineDefaultProperty(QStringLiteral("fromLocaleTimeString"), method_fromLocaleTimeString); - engine->dateCtor.objectValue()->defineDefaultProperty(QStringLiteral("fromLocaleDateString"), method_fromLocaleDateString); - engine->dateCtor.objectValue()->defineDefaultProperty(QStringLiteral("timeZoneUpdated"), method_timeZoneUpdated); + engine->datePrototype()->defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString); + engine->datePrototype()->defineDefaultProperty(QStringLiteral("toLocaleTimeString"), method_toLocaleTimeString); + engine->datePrototype()->defineDefaultProperty(QStringLiteral("toLocaleDateString"), method_toLocaleDateString); + engine->dateCtor()->defineDefaultProperty(QStringLiteral("fromLocaleString"), method_fromLocaleString); + engine->dateCtor()->defineDefaultProperty(QStringLiteral("fromLocaleTimeString"), method_fromLocaleTimeString); + engine->dateCtor()->defineDefaultProperty(QStringLiteral("fromLocaleDateString"), method_fromLocaleDateString); + engine->dateCtor()->defineDefaultProperty(QStringLiteral("timeZoneUpdated"), method_timeZoneUpdated); } QV4::ReturnedValue QQmlDateExtension::method_toLocaleString(QV4::CallContext *ctx) @@ -81,7 +81,7 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleString(QV4::CallContext *ct QV4::Scope scope(ctx); - QV4::DateObject *date = ctx->thisObject().asDateObject(); + QV4::DateObject *date = ctx->thisObject().as<DateObject>(); if (!date) return QV4::DatePrototype::method_toLocaleString(ctx); @@ -125,7 +125,7 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleTimeString(QV4::CallContext QV4::Scope scope(ctx); - QV4::DateObject *date = ctx->thisObject().asDateObject(); + QV4::DateObject *date = ctx->thisObject().as<DateObject>(); if (!date) return QV4::DatePrototype::method_toLocaleTimeString(ctx); @@ -170,7 +170,7 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleDateString(QV4::CallContext QV4::Scope scope(ctx); - QV4::DateObject *dateObj = ctx->thisObject().asDateObject(); + QV4::DateObject *dateObj = ctx->thisObject().as<DateObject>(); if (!dateObj) return QV4::DatePrototype::method_toLocaleDateString(ctx); @@ -347,9 +347,9 @@ QV4::ReturnedValue QQmlDateExtension::method_timeZoneUpdated(QV4::CallContext *c void QQmlNumberExtension::registerExtension(QV4::ExecutionEngine *engine) { - engine->numberPrototype.asObject()->defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString); - engine->numberPrototype.asObject()->defineDefaultProperty(QStringLiteral("toLocaleCurrencyString"), method_toLocaleCurrencyString); - engine->numberCtor.objectValue()->defineDefaultProperty(QStringLiteral("fromLocaleString"), method_fromLocaleString); + engine->numberPrototype()->defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString); + engine->numberPrototype()->defineDefaultProperty(QStringLiteral("toLocaleCurrencyString"), method_toLocaleCurrencyString); + engine->numberCtor()->defineDefaultProperty(QStringLiteral("fromLocaleString"), method_fromLocaleString); } QV4::ReturnedValue QQmlNumberExtension::method_toLocaleString(QV4::CallContext *ctx) @@ -815,15 +815,15 @@ QV4::ReturnedValue QQmlLocale::wrap(ExecutionEngine *v4, const QLocale &locale) void QQmlLocale::registerStringLocaleCompare(QV4::ExecutionEngine *engine) { - engine->stringPrototype.asObject()->defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare); + engine->stringPrototype()->defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare); } QV4::ReturnedValue QQmlLocale::method_localeCompare(QV4::CallContext *ctx) { - if (ctx->argc() != 1 || (!ctx->args()[0].isString() && !ctx->args()[0].asStringObject())) + if (ctx->argc() != 1 || (!ctx->args()[0].isString() && !ctx->args()[0].as<StringObject>())) return QV4::StringPrototype::method_localeCompare(ctx); - if (!ctx->thisObject().isString() && !ctx->thisObject().asStringObject()) + if (!ctx->thisObject().isString() && !ctx->thisObject().as<StringObject>()) return QV4::StringPrototype::method_localeCompare(ctx); QString thisString = ctx->thisObject().toQStringNoThrow(); diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h index d4436482cf..cb9fe9bbef 100644 --- a/src/qml/qml/qqmllocale_p.h +++ b/src/qml/qml/qqmllocale_p.h @@ -74,10 +74,6 @@ private: class Q_AUTOTEST_EXPORT QQmlLocale { Q_GADGET - Q_ENUMS(MeasurementSystem) - Q_ENUMS(FormatType) - Q_ENUMS(CurrencySymbolFormat) - Q_ENUMS(DayOfWeek) public: ~QQmlLocale(); @@ -88,16 +84,19 @@ public: ImperialUSSystem = QLocale::ImperialUSSystem, ImperialUKSystem = QLocale::ImperialUKSystem }; + Q_ENUM(MeasurementSystem) enum FormatType { LongFormat = QLocale::LongFormat, ShortFormat = QLocale::ShortFormat, NarrowFormat = QLocale::NarrowFormat }; + Q_ENUM(FormatType) enum CurrencySymbolFormat { CurrencyIsoCode = QLocale::CurrencyIsoCode, CurrencySymbol = QLocale::CurrencySymbol, CurrencyDisplayName = QLocale::CurrencyDisplayName }; + Q_ENUM(CurrencySymbolFormat) // Qt defines Sunday as 7, but JS Date assigns Sunday 0 enum DayOfWeek { Sunday = 0, @@ -108,6 +107,7 @@ public: Friday = Qt::Friday, Saturday = Qt::Saturday }; + Q_ENUM(DayOfWeek) static QV4::ReturnedValue locale(QV4::ExecutionEngine *engine, const QString &localeName); static QV4::ReturnedValue wrap(QV4::ExecutionEngine *engine, const QLocale &locale); @@ -137,7 +137,7 @@ struct QQmlLocaleData : public QV4::Object V4_NEEDS_DESTROY static QLocale *getThisLocale(QV4::CallContext *ctx) { - QV4::Object *o = ctx->thisObject().asObject(); + QV4::Object *o = ctx->thisObject().as<Object>(); QQmlLocaleData *thisObject = o ? o->as<QQmlLocaleData>() : 0; if (!thisObject) { ctx->engine()->throwTypeError(); diff --git a/src/qml/qml/qqmlmemoryprofiler.cpp b/src/qml/qml/qqmlmemoryprofiler.cpp index cdd60e2dec..531666340b 100644 --- a/src/qml/qml/qqmlmemoryprofiler.cpp +++ b/src/qml/qml/qqmlmemoryprofiler.cpp @@ -63,11 +63,13 @@ static qmlmemprofile_pop_location *memprofile_pop_location; static qmlmemprofile_save *memprofile_save; static qmlmemprofile_is_enabled *memprofile_is_enabled; +#ifndef QT_NO_LIBRARY extern QFunctionPointer qt_linux_find_symbol_sys(const char *symbol); +#endif static bool openLibrary() { -#ifdef Q_OS_LINUX +#if defined(Q_OS_LINUX) && !defined(QT_NO_LIBRARY) if (state == Unloaded) { memprofile_stats = (qmlmemprofile_stats *) qt_linux_find_symbol_sys("qmlmemprofile_stats"); memprofile_clear = (qmlmemprofile_clear *) qt_linux_find_symbol_sys("qmlmemprofile_clear"); diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index cb8c2bd3b5..fbb21f4562 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -258,7 +258,7 @@ QObject *QQmlType::SingletonInstanceInfo::qobjectApi(QQmlEngine *e) const return qobjectApis.value(e); } -void QQmlType::SingletonInstanceInfo::setScriptApi(QQmlEngine *e, QJSValue v) +void QQmlType::SingletonInstanceInfo::setScriptApi(QQmlEngine *e, const QJSValue &v) { scriptApis.insert(e, v); } @@ -1110,7 +1110,9 @@ void qmlClearTypeRegistrations() // Declared in qqml.h data->uriToModule.clear(); QQmlEnginePrivate::baseModulesUninitialized = true; //So the engine re-registers its types +#ifndef QT_NO_LIBRARY qmlClearEnginePlugins(); +#endif } int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent) @@ -1440,8 +1442,8 @@ bool QQmlMetaType::isAnyModule(const QString &uri) QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin(); - iter != data->uriToModule.end(); ++iter) { + for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.cbegin(); + iter != data->uriToModule.cend(); ++iter) { if ((*iter)->module() == uri) return true; } @@ -1718,7 +1720,7 @@ QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStrin QQmlMetaTypeData *data = metaTypeData(); QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.constFind(name); - while (it != data->nameToType.end() && it.key() == name) { + while (it != data->nameToType.cend() && it.key() == name) { // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty if (version_major < 0 || module.isEmpty() || (*it)->availableInVersion(module, version_major,version_minor)) return (*it); @@ -1752,7 +1754,7 @@ QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStri QQmlMetaTypeData *data = metaTypeData(); QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.constFind(metaObject); - while (it != data->metaObjectToType.end() && it.key() == metaObject) { + while (it != data->metaObjectToType.cend() && it.key() == metaObject) { QQmlType *t = *it; if (version_major < 0 || module.isEmpty() || t->availableInVersion(module, version_major,version_minor)) return t; @@ -1823,8 +1825,9 @@ QList<QString> QQmlMetaType::qmlTypeNames() QQmlMetaTypeData *data = metaTypeData(); QList<QString> names; - QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.begin(); - while (it != data->nameToType.end()) { + names.reserve(data->nameToType.count()); + QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.cbegin(); + while (it != data->nameToType.cend()) { names += (*it)->qmlTypeName(); ++it; } diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index e5ac20d314..61a6567f1d 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -191,7 +191,7 @@ public: void setQObjectApi(QQmlEngine *, QObject *); QObject *qobjectApi(QQmlEngine *) const; - void setScriptApi(QQmlEngine *, QJSValue); + void setScriptApi(QQmlEngine *, const QJSValue &); QJSValue scriptApi(QQmlEngine *) const; void init(QQmlEngine *); diff --git a/src/qml/qml/qqmlnotifier_p.h b/src/qml/qml/qqmlnotifier_p.h index 2742bfc84b..90902c089d 100644 --- a/src/qml/qml/qqmlnotifier_p.h +++ b/src/qml/qml/qqmlnotifier_p.h @@ -63,9 +63,6 @@ class QQmlNotifierEndpoint QQmlNotifierEndpoint *next; QQmlNotifierEndpoint **prev; public: - inline QQmlNotifierEndpoint(); - inline ~QQmlNotifierEndpoint(); - // QQmlNotifierEndpoint can only invoke one of a set of pre-defined callbacks. // To add another callback, extend this enum and add the callback to the top // of qqmlnotifier.cpp. Four bits are reserved for the callback, so there can @@ -77,7 +74,8 @@ public: QQmlVMEMetaObjectEndpoint = 3 }; - inline void setCallback(Callback c) { callback = c; } + inline QQmlNotifierEndpoint(Callback callback); + inline ~QQmlNotifierEndpoint(); inline bool isConnected(); inline bool isConnected(QObject *source, int sourceSignal); @@ -90,6 +88,8 @@ public: inline bool isNotifying() const; inline void cancelNotify(); + inline int signalIndex() const { return sourceSignal; } + private: friend class QQmlData; friend class QQmlNotifier; @@ -135,8 +135,8 @@ void QQmlNotifier::notify() if (endpoints) emitNotify(endpoints, args); } -QQmlNotifierEndpoint::QQmlNotifierEndpoint() -: next(0), prev(0), senderPtr(0), callback(None), sourceSignal(-1) +QQmlNotifierEndpoint::QQmlNotifierEndpoint(Callback callback) +: next(0), prev(0), senderPtr(0), callback(callback), sourceSignal(-1) { } diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 3c2f3690b9..0b977f2551 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -62,14 +62,6 @@ struct ActiveOCRestorer }; } -static void removeBindingOnProperty(QObject *o, int index) -{ - int coreIndex; - int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(index, &coreIndex); - QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(o, coreIndex, valueTypeIndex, 0); - if (binding) binding->destroy(); -} - QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlContextData *creationContext, void *activeVMEDataForRootContext) : phase(Startup) , compiledData(compiledData) @@ -137,11 +129,6 @@ QQmlObjectCreator::~QQmlObjectCreator() { QQmlObjectCreatorRecursionWatcher watcher(this); } - for (int i = 0; i < sharedState->allCreatedBindings.count(); ++i) { - QQmlAbstractBinding *b = sharedState->allCreatedBindings.at(i); - if (b) - b->m_mePtr = 0; - } for (int i = 0; i < sharedState->allParserStatusCallbacks.count(); ++i) { QQmlParserStatus *ps = sharedState->allParserStatusCallbacks.at(i); if (ps) @@ -660,15 +647,12 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip) // ### this is best done through type-compile-time binding skip lists. if (_valueTypeProperty) { - QQmlAbstractBinding *binding = - QQmlPropertyPrivate::binding(_bindingTarget, _valueTypeProperty->coreIndex, -1); + QQmlAbstractBinding *binding = QQmlPropertyPrivate::binding(_bindingTarget, _valueTypeProperty->coreIndex); - if (binding && binding->bindingType() != QQmlAbstractBinding::ValueTypeProxy) { - QQmlPropertyPrivate::setBinding(_bindingTarget, _valueTypeProperty->coreIndex, -1, 0); - binding->destroy(); + if (binding && !binding->isValueTypeProxy()) { + QQmlPropertyPrivate::removeBinding(_bindingTarget, _valueTypeProperty->coreIndex); } else if (binding) { - QQmlValueTypeProxyBinding *proxy = - static_cast<QQmlValueTypeProxyBinding *>(binding); + QQmlValueTypeProxyBinding *proxy = static_cast<QQmlValueTypeProxyBinding *>(binding); if (qmlTypeForObject(_bindingTarget)) { quint32 bindingSkipList = 0; @@ -731,7 +715,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con // ### resolve this at compile time if (property && property->propType == qMetaTypeId<QQmlScriptString>()) { QQmlScriptString ss(binding->valueAsScriptString(qmlUnit), context->asQQmlContext(), _scopeObject); - ss.d.data()->bindingId = binding->type == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : QQmlBinding::Invalid; + ss.d.data()->bindingId = binding->type == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : (quint32)QQmlBinding::Invalid; ss.d.data()->lineNumber = binding->location.line; ss.d.data()->columnNumber = binding->location.column; ss.d.data()->isStringLiteral = binding->type == QV4::CompiledData::Binding::Type_String; @@ -800,7 +784,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con if (_ddata->hasBindingBit(property->coreIndex) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment) && !_valueTypeProperty) - removeBindingOnProperty(_bindingTarget, property->coreIndex); + QQmlPropertyPrivate::removeBinding(_bindingTarget, property->coreIndex); if (binding->type == QV4::CompiledData::Binding::Type_Script) { QV4::Function *runtimeFunction = compiledData->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]; @@ -828,18 +812,12 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con if (_valueTypeProperty) targetCorePropertyData = QQmlPropertyPrivate::saveValueType(*_valueTypeProperty, _qobject->metaObject(), property->coreIndex, engine); - sharedState->allCreatedBindings.push(qmlBinding); - qmlBinding->m_mePtr = &sharedState->allCreatedBindings.top(); + sharedState->allCreatedBindings.push(QQmlAbstractBinding::Ptr(qmlBinding)); - qmlBinding->setTarget(_bindingTarget, targetCorePropertyData, context); + qmlBinding->setTarget(_bindingTarget, targetCorePropertyData); if (targetCorePropertyData.isAlias()) { - QQmlAbstractBinding *old = - QQmlPropertyPrivate::setBindingNoEnable(_bindingTarget, - targetCorePropertyData.coreIndex, - targetCorePropertyData.getValueTypeCoreIndex(), - qmlBinding); - if (old) { old->destroy(); } + QQmlPropertyPrivate::setBinding(qmlBinding, QQmlPropertyPrivate::DontEnable); } else { qmlBinding->addToObject(); @@ -1011,7 +989,7 @@ QV4::Heap::ExecutionContext *QQmlObjectCreator::currentQmlContext() { if (!_qmlBindingWrapper->objectValue()) { QV4::Scope valueScope(v4); - QV4::ScopedObject qmlScope(valueScope, QV4::QmlContextWrapper::qmlScope(v4, context, _scopeObject)); + QV4::Scoped<QV4::QmlContextWrapper> qmlScope(valueScope, QV4::QmlContextWrapper::qmlScope(v4, context, _scopeObject)); QV4::ScopedContext global(valueScope, v4->rootContext()); *_qmlBindingWrapper = v4->memoryManager->alloc<QV4::QmlBindingWrapper>(global, qmlScope); } @@ -1124,7 +1102,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo QBitArray bindingsToSkip; if (customParser) { - QHash<int, QBitArray>::ConstIterator customParserBindings = compiledData->customParserBindings.find(index); + QHash<int, QBitArray>::ConstIterator customParserBindings = compiledData->customParserBindings.constFind(index); if (customParserBindings != compiledData->customParserBindings.constEnd()) { customParser->imports = compiledData->importCache; @@ -1183,13 +1161,14 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine)); while (!sharedState->allCreatedBindings.isEmpty()) { - QQmlAbstractBinding *b = sharedState->allCreatedBindings.pop(); - if (!b) + QQmlAbstractBinding::Ptr b = sharedState->allCreatedBindings.pop(); + Q_ASSERT(b); + // skip, if b is not added to an object + if (!b->isAddedToObject()) continue; - b->m_mePtr = 0; - QQmlData *data = QQmlData::get(b->object()); + QQmlData *data = QQmlData::get(b->targetObject()); Q_ASSERT(data); - data->clearPendingBindingBit(b->propertyIndex()); + data->clearPendingBindingBit(b->targetPropertyIndex()); b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); @@ -1299,7 +1278,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * QBitArray bindingSkipList = bindingsToSkip; { - QHash<int, QBitArray>::ConstIterator deferredBindings = compiledData->deferredBindingsPerObject.find(_compiledObjectIndex); + QHash<int, QBitArray>::ConstIterator deferredBindings = compiledData->deferredBindingsPerObject.constFind(_compiledObjectIndex); if (deferredBindings != compiledData->deferredBindingsPerObject.constEnd()) { if (bindingSkipList.isEmpty()) bindingSkipList.resize(deferredBindings->count()); diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index 60fefe494f..c88c15b525 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -55,7 +55,7 @@ struct QQmlObjectCreatorSharedState : public QSharedData { QQmlContextData *rootContext; QQmlContextData *creationContext; - QFiniteStack<QQmlAbstractBinding*> allCreatedBindings; + QFiniteStack<QQmlAbstractBinding::Ptr> allCreatedBindings; QFiniteStack<QQmlParserStatus*> allParserStatusCallbacks; QFiniteStack<QPointer<QObject> > allCreatedObjects; QV4::Value *allJavaScriptObjects; // pointer to vector on JS stack to reference JS wrappers during creation phase. diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp index fc24b15fd2..c6d2d44ee1 100644 --- a/src/qml/qml/qqmlopenmetaobject.cpp +++ b/src/qml/qml/qqmlopenmetaobject.cpp @@ -277,8 +277,8 @@ void QQmlOpenMetaObject::setValue(int id, const QVariant &value) QVariant QQmlOpenMetaObject::value(const QByteArray &name) const { - QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.find(name); - if (iter == d->type->d->names.end()) + QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.constFind(name); + if (iter == d->type->d->names.cend()) return QVariant(); return d->getData(*iter); @@ -286,8 +286,8 @@ QVariant QQmlOpenMetaObject::value(const QByteArray &name) const QVariant &QQmlOpenMetaObject::operator[](const QByteArray &name) { - QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.find(name); - Q_ASSERT(iter != d->type->d->names.end()); + QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.constFind(name); + Q_ASSERT(iter != d->type->d->names.cend()); return d->getData(*iter); } @@ -299,10 +299,10 @@ QVariant &QQmlOpenMetaObject::operator[](int id) bool QQmlOpenMetaObject::setValue(const QByteArray &name, const QVariant &val) { - QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.find(name); + QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.constFind(name); int id = -1; - if (iter == d->type->d->names.end()) { + if (iter == d->type->d->names.cend()) { id = createProperty(name.constData(), "") - d->type->d->propertyOffset; } else { id = *iter; diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 800f650075..c1120b4542 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -55,6 +55,7 @@ #include <private/qmetaobject_p.h> #include <private/qqmlvaluetypewrapper_p.h> #include <QtCore/qdebug.h> +#include <cmath> Q_DECLARE_METATYPE(QList<int>) Q_DECLARE_METATYPE(QList<qreal>) @@ -699,8 +700,7 @@ QQmlPropertyPrivate::binding(const QQmlProperty &that) if (!that.d || !that.isProperty() || !that.d->object) return 0; - return binding(that.d->object, that.d->core.coreIndex, - that.d->core.getValueTypeCoreIndex()); + return binding(that.d->object, that.d->core.encodedIndex()); } /*! @@ -716,65 +716,96 @@ QQmlPropertyPrivate::binding(const QQmlProperty &that) \a flags is passed through to the binding and is used for the initial update (when the binding sets the initial value, it will use these flags for the write). */ -QQmlAbstractBinding * -QQmlPropertyPrivate::setBinding(const QQmlProperty &that, - QQmlAbstractBinding *newBinding, - WriteFlags flags) +void +QQmlPropertyPrivate::setBinding(const QQmlProperty &that, QQmlAbstractBinding *newBinding) { + if (!newBinding) { + removeBinding(that); + return; + } + if (!that.d || !that.isProperty() || !that.d->object) { - if (newBinding) - newBinding->destroy(); - return 0; + if (!newBinding->ref) + delete newBinding; + return; } + setBinding(newBinding); +} + +static void removeOldBinding(QObject *object, int index, QQmlPropertyPrivate::BindingFlags flags = QQmlPropertyPrivate::None) +{ + int coreIndex; + int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(index, &coreIndex); - if (newBinding) { - // In the case that the new binding is provided, we must target the property it - // is associated with. If we don't do this, retargetBinding() can fail. - QObject *object = newBinding->object(); - int pi = newBinding->propertyIndex(); + QQmlData *data = QQmlData::get(object, false); - int core; - int vt = QQmlPropertyData::decodeValueTypePropertyIndex(pi, &core); + if (!data || !data->hasBindingBit(coreIndex)) + return; - return setBinding(object, core, vt, newBinding, flags); - } else { - return setBinding(that.d->object, that.d->core.coreIndex, - that.d->core.getValueTypeCoreIndex(), - newBinding, flags); - } + QQmlAbstractBinding::Ptr oldBinding; + oldBinding = data->bindings; + + while (oldBinding && oldBinding->targetPropertyIndex() != coreIndex) + oldBinding = oldBinding->nextBinding(); + + if (!oldBinding) + return; + + if (valueTypeIndex != -1 && oldBinding->isValueTypeProxy()) + oldBinding = static_cast<QQmlValueTypeProxyBinding *>(oldBinding.data())->binding(index); + + if (!oldBinding) + return; + + if (!(flags & QQmlPropertyPrivate::DontEnable)) + oldBinding->setEnabled(false, 0); + oldBinding->removeFromObject(); +} + +void QQmlPropertyPrivate::removeBinding(QQmlAbstractBinding *b) +{ + removeBinding(b->targetObject(), b->targetPropertyIndex()); +} + +void QQmlPropertyPrivate::removeBinding(QObject *o, int index) +{ + Q_ASSERT(o); + + QObject *target; + int targetIndex; + findAliasTarget(o, index, &target, &targetIndex); + removeOldBinding(target, targetIndex); +} + +void QQmlPropertyPrivate::removeBinding(const QQmlProperty &that) +{ + if (!that.d || !that.isProperty() || !that.d->object) + return; + + removeBinding(that.d->object, that.d->core.encodedIndex()); } QQmlAbstractBinding * -QQmlPropertyPrivate::binding(QObject *object, int coreIndex, int valueTypeIndex) +QQmlPropertyPrivate::binding(QObject *object, int index) { QQmlData *data = QQmlData::get(object); if (!data) return 0; - QQmlPropertyData *propertyData = - data->propertyCache?data->propertyCache->property(coreIndex):0; - if (propertyData && propertyData->isAlias()) { - QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex); + findAliasTarget(object, index, &object, &index); - QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1; - if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex) || aCoreIndex == -1) - return 0; - - // This will either be a value type sub-reference or an alias to a value-type sub-reference not both - Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1); - aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex; - return binding(aObject, aCoreIndex, aValueTypeIndex); - } + int coreIndex; + int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(index, &coreIndex); if (!data->hasBindingBit(coreIndex)) return 0; QQmlAbstractBinding *binding = data->bindings; - while (binding && binding->propertyIndex() != coreIndex) + while (binding && binding->targetPropertyIndex() != coreIndex) binding = binding->nextBinding(); if (binding && valueTypeIndex != -1) { - if (binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy) { + if (binding->isValueTypeProxy()) { int index = QQmlPropertyData::encodeValueTypePropertyIndex(coreIndex, valueTypeIndex); binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index); } @@ -786,11 +817,11 @@ QQmlPropertyPrivate::binding(QObject *object, int coreIndex, int valueTypeIndex) void QQmlPropertyPrivate::findAliasTarget(QObject *object, int bindingIndex, QObject **targetObject, int *targetBindingIndex) { - int coreIndex; - int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(bindingIndex, &coreIndex); - QQmlData *data = QQmlData::get(object, false); if (data) { + int coreIndex; + int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(bindingIndex, &coreIndex); + QQmlPropertyData *propertyData = data->propertyCache?data->propertyCache->property(coreIndex):0; if (propertyData && propertyData->isAlias()) { @@ -817,119 +848,30 @@ void QQmlPropertyPrivate::findAliasTarget(QObject *object, int bindingIndex, *targetBindingIndex = bindingIndex; } -QQmlAbstractBinding * -QQmlPropertyPrivate::setBinding(QObject *object, int coreIndex, int valueTypeIndex, - QQmlAbstractBinding *newBinding, WriteFlags flags) -{ - QQmlData *data = QQmlData::get(object, 0 != newBinding); - QQmlAbstractBinding *binding = 0; - - if (data) { - QQmlPropertyData *propertyData = - data->propertyCache?data->propertyCache->property(coreIndex):0; - if (propertyData && propertyData->isAlias()) { - QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex); - - QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1; - if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) { - if (newBinding) newBinding->destroy(); - return 0; - } - - // This will either be a value type sub-reference or an alias to a value-type sub-reference not both - Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1); - aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex; - return setBinding(aObject, aCoreIndex, aValueTypeIndex, newBinding, flags); - } - } - - if (data && data->hasBindingBit(coreIndex)) { - binding = data->bindings; - - while (binding && binding->propertyIndex() != coreIndex) - binding = binding->nextBinding(); - } - - int index = coreIndex; - if (valueTypeIndex != -1) - index = QQmlPropertyData::encodeValueTypePropertyIndex(index, valueTypeIndex); - - if (binding && valueTypeIndex != -1 && binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy) - binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index); - - if (binding) { - binding->removeFromObject(); - binding->setEnabled(false, 0); - } - - if (newBinding) { - if (newBinding->propertyIndex() != index || newBinding->object() != object) - newBinding->retargetBinding(object, index); - - Q_ASSERT(newBinding->propertyIndex() == index); - Q_ASSERT(newBinding->object() == object); - - newBinding->addToObject(); - newBinding->setEnabled(true, flags); - } - - return binding; -} -QQmlAbstractBinding * -QQmlPropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valueTypeIndex, - QQmlAbstractBinding *newBinding) +void QQmlPropertyPrivate::setBinding(QQmlAbstractBinding *binding, BindingFlags flags, WriteFlags writeFlags) { - QQmlData *data = QQmlData::get(object, 0 != newBinding); - QQmlAbstractBinding *binding = 0; - - if (data) { - QQmlPropertyData *propertyData = - data->propertyCache?data->propertyCache->property(coreIndex):0; - if (propertyData && propertyData->isAlias()) { - QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex); - - QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1; - if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) { - if (newBinding) newBinding->destroy(); - return 0; - } + Q_ASSERT(binding); - // This will either be a value type sub-reference or an alias to a value-type sub-reference not both - Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1); - aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex; - return setBindingNoEnable(aObject, aCoreIndex, aValueTypeIndex, newBinding); - } - } + QObject *object = binding->targetObject(); + int index = binding->targetPropertyIndex(); - if (data && data->hasBindingBit(coreIndex)) { - binding = data->bindings; - - while (binding && binding->propertyIndex() != coreIndex) - binding = binding->nextBinding(); +#ifndef QT_NO_DEBUG + int coreIndex; + QQmlPropertyData::decodeValueTypePropertyIndex(index, &coreIndex); + QQmlData *data = QQmlData::get(object, true); + if (data->propertyCache) { + QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex); + Q_ASSERT(propertyData && !propertyData->isAlias()); } +#endif - int index = coreIndex; - if (valueTypeIndex != -1) - index = QQmlPropertyData::encodeValueTypePropertyIndex(index, valueTypeIndex); - - if (binding && valueTypeIndex != -1 && binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy) - binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index); - - if (binding) - binding->removeFromObject(); - - if (newBinding) { - if (newBinding->propertyIndex() != index || newBinding->object() != object) - newBinding->retargetBinding(object, index); - - Q_ASSERT(newBinding->propertyIndex() == index); - Q_ASSERT(newBinding->object() == object); + removeOldBinding(object, index, flags); - newBinding->addToObject(); - } + binding->addToObject(); + if (!(flags & DontEnable)) + binding->setEnabled(true, writeFlags); - return binding; } /*! @@ -946,9 +888,9 @@ QQmlPropertyPrivate::signalExpression(const QQmlProperty &that) if (!data) return 0; - QQmlAbstractBoundSignal *signalHandler = data->signalHandlers; + QQmlBoundSignal *signalHandler = data->signalHandlers; - while (signalHandler && signalHandler->index() != QQmlPropertyPrivate::get(that)->signalIndex()) + while (signalHandler && signalHandler->signalIndex() != QQmlPropertyPrivate::get(that)->signalIndex()) signalHandler = signalHandler->m_nextSignal; if (signalHandler) @@ -959,48 +901,41 @@ QQmlPropertyPrivate::signalExpression(const QQmlProperty &that) /*! Set the signal expression associated with this signal property to \a expr. - Returns the existing signal expression (if any), otherwise null. - - A reference to \a expr will be added by QML. Ownership of the return value - reference is assumed by the caller. + A reference to \a expr will be added by QML. */ -QQmlBoundSignalExpressionPointer -QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that, - QQmlBoundSignalExpression *expr) +void QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that, QQmlBoundSignalExpression *expr) { if (expr) expr->addref(); - return QQmlPropertyPrivate::takeSignalExpression(that, expr); + QQmlPropertyPrivate::takeSignalExpression(that, expr); } /*! Set the signal expression associated with this signal property to \a expr. - Returns the existing signal expression (if any), otherwise null. - - Ownership of \a expr transfers to QML. Ownership of the return value - reference is assumed by the caller. + Ownership of \a expr transfers to QML. */ -QQmlBoundSignalExpressionPointer -QQmlPropertyPrivate::takeSignalExpression(const QQmlProperty &that, +void QQmlPropertyPrivate::takeSignalExpression(const QQmlProperty &that, QQmlBoundSignalExpression *expr) { if (!(that.type() & QQmlProperty::SignalProperty)) { if (expr) expr->release(); - return 0; + return; } QQmlData *data = QQmlData::get(that.d->object, 0 != expr); if (!data) - return 0; + return; - QQmlAbstractBoundSignal *signalHandler = data->signalHandlers; + QQmlBoundSignal *signalHandler = data->signalHandlers; - while (signalHandler && signalHandler->index() != QQmlPropertyPrivate::get(that)->signalIndex()) + while (signalHandler && signalHandler->signalIndex() != QQmlPropertyPrivate::get(that)->signalIndex()) signalHandler = signalHandler->m_nextSignal; - if (signalHandler) - return signalHandler->takeExpression(expr); + if (signalHandler) { + signalHandler->takeExpression(expr); + return; + } if (expr) { int signalIndex = QQmlPropertyPrivate::get(that)->signalIndex(); @@ -1008,7 +943,6 @@ QQmlPropertyPrivate::takeSignalExpression(const QQmlProperty &that, expr->context()->engine); signal->takeExpression(expr); } - return 0; } /*! @@ -1125,7 +1059,7 @@ QVariant QQmlPropertyPrivate::readValueProperty() } // helper function to allow assignment / binding to QList<QUrl> properties. -static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *context) +QVariant QQmlPropertyPrivate::resolvedUrlSequence(const QVariant &value, QQmlContextData *context) { QList<QUrl> urls; if (value.userType() == qMetaTypeId<QUrl>()) { @@ -1138,16 +1072,22 @@ static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *cont urls = value.value<QList<QUrl> >(); } else if (value.userType() == qMetaTypeId<QStringList>()) { QStringList urlStrings = value.value<QStringList>(); - for (int i = 0; i < urlStrings.size(); ++i) + const int urlStringsSize = urlStrings.size(); + urls.reserve(urlStringsSize); + for (int i = 0; i < urlStringsSize; ++i) urls.append(QUrl(urlStrings.at(i))); } else if (value.userType() == qMetaTypeId<QList<QString> >()) { QList<QString> urlStrings = value.value<QList<QString> >(); - for (int i = 0; i < urlStrings.size(); ++i) + const int urlStringsSize = urlStrings.size(); + urls.reserve(urlStringsSize); + for (int i = 0; i < urlStringsSize; ++i) urls.append(QUrl(urlStrings.at(i))); } // note: QList<QByteArray> is not currently supported. QList<QUrl> resolvedUrls; - for (int i = 0; i < urls.size(); ++i) { + const int urlsSize = urls.size(); + resolvedUrls.reserve(urlsSize); + for (int i = 0; i < urlsSize; ++i) { QUrl u = urls.at(i); if (context && u.isRelative() && !u.isEmpty()) u = context->resolvedUrl(u); @@ -1210,12 +1150,8 @@ QQmlPropertyPrivate::writeValueProperty(QObject *object, QQmlContextData *context, WriteFlags flags) { // Remove any existing bindings on this property - if (!(flags & DontRemoveBinding) && object) { - QQmlAbstractBinding *binding = setBinding(object, core.coreIndex, - core.getValueTypeCoreIndex(), - 0, flags); - if (binding) binding->destroy(); - } + if (!(flags & DontRemoveBinding) && object) + removeBinding(object, core.encodedIndex()); bool rv = false; if (core.isValueTypeVirtual()) { @@ -1255,7 +1191,7 @@ bool QQmlPropertyPrivate::write(QObject *object, // Enum values come through the script engine as doubles if (value.userType() == QVariant::Double) { double integral; - double fractional = modf(value.toDouble(), &integral); + double fractional = std::modf(value.toDouble(), &integral); if (qFuzzyIsNull(fractional)) v.convert(QVariant::Int); } @@ -1475,166 +1411,6 @@ bool QQmlPropertyPrivate::write(QObject *object, return true; } -// Returns true if successful, false if an error description was set on expression -bool QQmlPropertyPrivate::writeBinding(QObject *object, - const QQmlPropertyData &core, - QQmlContextData *context, - QQmlJavaScriptExpression *expression, - const QV4::Value &result, bool isUndefined, - WriteFlags flags) -{ - Q_ASSERT(object); - Q_ASSERT(core.coreIndex != -1); - - QQmlEngine *engine = context->engine; - QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine); - -#define QUICK_STORE(cpptype, conversion) \ - { \ - cpptype o = (conversion); \ - int status = -1; \ - void *argv[] = { &o, 0, &status, &flags }; \ - QMetaObject::metacall(object, QMetaObject::WriteProperty, core.coreIndex, argv); \ - return true; \ - } \ - - - if (!isUndefined && !core.isValueTypeVirtual()) { - switch (core.propType) { - case QMetaType::Int: - if (result.isInteger()) - QUICK_STORE(int, result.integerValue()) - else if (result.isNumber()) - QUICK_STORE(int, result.doubleValue()) - break; - case QMetaType::Double: - if (result.isNumber()) - QUICK_STORE(double, result.asDouble()) - break; - case QMetaType::Float: - if (result.isNumber()) - QUICK_STORE(float, result.asDouble()) - break; - case QMetaType::QString: - if (result.isString()) - QUICK_STORE(QString, result.toQStringNoThrow()) - break; - default: - if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) { - if (vtw->d()->valueType->typeId == core.propType) { - return vtw->write(object, core.coreIndex); - } - } - break; - } - } -#undef QUICK_STORE - - int type = core.isValueTypeVirtual()?core.valueTypePropType:core.propType; - - QQmlJavaScriptExpression::DeleteWatcher watcher(expression); - - QVariant value; - bool isVarProperty = core.isVarProperty(); - - if (isUndefined) { - } else if (core.isQList()) { - value = QV8Engine::getV4(v8engine)->toVariant(result, qMetaTypeId<QList<QObject *> >()); - } else if (result.isNull() && core.isQObject()) { - value = QVariant::fromValue((QObject *)0); - } else if (core.propType == qMetaTypeId<QList<QUrl> >()) { - value = resolvedUrlSequence(QV8Engine::getV4(v8engine)->toVariant(result, qMetaTypeId<QList<QUrl> >()), context); - } else if (!isVarProperty && type != qMetaTypeId<QJSValue>()) { - value = QV8Engine::getV4(v8engine)->toVariant(result, type); - } - - if (expression->hasError()) { - return false; - } else if (isVarProperty) { - QV4::FunctionObject *f = result.asFunctionObject(); - if (f && f->isBinding()) { - // we explicitly disallow this case to avoid confusion. Users can still store one - // in an array in a var property if they need to, but the common case is user error. - expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); - expression->delayedError()->setErrorObject(object); - return false; - } - - QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); - Q_ASSERT(vmemo); - vmemo->setVMEProperty(core.coreIndex, result); - } else if (isUndefined && core.isResettable()) { - void *args[] = { 0 }; - QMetaObject::metacall(object, QMetaObject::ResetProperty, core.coreIndex, args); - } else if (isUndefined && type == qMetaTypeId<QVariant>()) { - writeValueProperty(object, core, QVariant(), context, flags); - } else if (type == qMetaTypeId<QJSValue>()) { - QV4::FunctionObject *f = result.asFunctionObject(); - if (f && f->isBinding()) { - expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); - expression->delayedError()->setErrorObject(object); - return false; - } - writeValueProperty(object, core, QVariant::fromValue( - QJSValue(QV8Engine::getV4(v8engine), result.asReturnedValue())), - context, flags); - } else if (isUndefined) { - QString errorStr = QLatin1String("Unable to assign [undefined] to "); - if (!QMetaType::typeName(type)) - errorStr += QLatin1String("[unknown property type]"); - else - errorStr += QLatin1String(QMetaType::typeName(type)); - expression->delayedError()->setErrorDescription(errorStr); - expression->delayedError()->setErrorObject(object); - return false; - } else if (QV4::FunctionObject *f = result.asFunctionObject()) { - if (f->isBinding()) - expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); - else - expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign a function to a property of any type other than var.")); - expression->delayedError()->setErrorObject(object); - return false; - } else if (!writeValueProperty(object, core, value, context, flags)) { - - if (watcher.wasDeleted()) - return true; - - const char *valueType = 0; - const char *propertyType = 0; - - if (value.userType() == QMetaType::QObjectStar) { - if (QObject *o = *(QObject *const *)value.constData()) { - valueType = o->metaObject()->className(); - - QQmlMetaObject propertyMetaObject = rawMetaObjectForType(QQmlEnginePrivate::get(engine), type); - if (!propertyMetaObject.isNull()) - propertyType = propertyMetaObject.className(); - } - } else if (value.userType() != QVariant::Invalid) { - if (value.userType() == QMetaType::VoidStar) - valueType = "null"; - else - valueType = QMetaType::typeName(value.userType()); - } - - if (!valueType) - valueType = "undefined"; - if (!propertyType) - propertyType = QMetaType::typeName(type); - if (!propertyType) - propertyType = "[unknown property type]"; - - expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign ") + - QLatin1String(valueType) + - QLatin1String(" to ") + - QLatin1String(propertyType)); - expression->delayedError()->setErrorObject(object); - return false; - } - - return true; -} - QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engine, int userType) { QMetaType metaType(userType); diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h index 98e310ebce..51a1db7b90 100644 --- a/src/qml/qml/qqmlproperty_p.h +++ b/src/qml/qml/qqmlproperty_p.h @@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE class QQmlContext; class QQmlEnginePrivate; class QQmlJavaScriptExpression; + class Q_QML_PRIVATE_EXPORT QQmlPropertyPrivate : public QQmlRefCount { public: @@ -103,15 +104,18 @@ public: QQmlContextData *, WriteFlags flags = 0); static void findAliasTarget(QObject *, int, QObject **, int *); - static QQmlAbstractBinding *setBinding(QObject *, int coreIndex, - int valueTypeIndex /* -1 */, - QQmlAbstractBinding *, - WriteFlags flags = DontRemoveBinding); - static QQmlAbstractBinding *setBindingNoEnable(QObject *, int coreIndex, - int valueTypeIndex /* -1 */, - QQmlAbstractBinding *); - static QQmlAbstractBinding *binding(QObject *, int coreIndex, - int valueTypeIndex /* -1 */); + enum BindingFlag { + None = 0, + DontEnable = 0x1 + }; + Q_DECLARE_FLAGS(BindingFlags, BindingFlag) + + static void setBinding(QQmlAbstractBinding *binding, BindingFlags flags = None, WriteFlags writeFlags = DontRemoveBinding); + + static void removeBinding(const QQmlProperty &that); + static void removeBinding(QObject *o, int index); + static void removeBinding(QQmlAbstractBinding *b); + static QQmlAbstractBinding *binding(QObject *, int index); static QQmlPropertyData saveValueType(const QQmlPropertyData &, const QMetaObject *, int, @@ -128,20 +132,13 @@ public: // "Public" (to QML) methods static QQmlAbstractBinding *binding(const QQmlProperty &that); - static QQmlAbstractBinding *setBinding(const QQmlProperty &that, - QQmlAbstractBinding *, - WriteFlags flags = DontRemoveBinding); + static void setBinding(const QQmlProperty &that, QQmlAbstractBinding *); static QQmlBoundSignalExpression *signalExpression(const QQmlProperty &that); - static QQmlBoundSignalExpressionPointer setSignalExpression(const QQmlProperty &that, + static void setSignalExpression(const QQmlProperty &that, QQmlBoundSignalExpression *); - static QQmlBoundSignalExpressionPointer takeSignalExpression(const QQmlProperty &that, + static void takeSignalExpression(const QQmlProperty &that, QQmlBoundSignalExpression *); static bool write(const QQmlProperty &that, const QVariant &, WriteFlags); - static bool writeBinding(QObject *, const QQmlPropertyData &, - QQmlContextData *context, - QQmlJavaScriptExpression *expression, - const QV4::Value &result, bool isUndefined, - WriteFlags flags); static int valueTypeCoreIndex(const QQmlProperty &that); static int bindingIndex(const QQmlProperty &that); static int bindingIndex(const QQmlPropertyData &that); @@ -150,9 +147,12 @@ public: const QObject *receiver, int method_index, int type = 0, int *types = 0); static void flushSignal(const QObject *sender, int signal_index); + + static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *context); }; Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyPrivate::WriteFlags) +Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyPrivate::BindingFlags) QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 0018275b95..cd8eb0d3e2 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -42,7 +42,7 @@ #include <private/qqmlaccessors_p.h> #include <private/qmetaobjectbuilder_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <QtCore/qdebug.h> @@ -837,7 +837,7 @@ void QQmlPropertyCache::updateRecur(const QMetaObject *metaObject) void QQmlPropertyCache::update(const QMetaObject *metaObject) { Q_ASSERT(metaObject); - Q_ASSERT(stringCache.isEmpty()); + stringCache.clear(); // Preallocate enough space in the index caches for all the properties/methods/signals that // are not cached in a parent cache so that the caches never need to be reallocated as this @@ -862,7 +862,6 @@ void QQmlPropertyCache::update(const QMetaObject *metaObject) */ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject) { - stringCache.clear(); propertyIndexCache.clear(); methodIndexCache.clear(); signalHandlerIndexCache.clear(); diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index 6ed9ec0d36..4d8c6dd9a5 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -54,7 +54,7 @@ #include <QtCore/qvarlengtharray.h> #include <QtCore/qvector.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> QT_BEGIN_NAMESPACE @@ -174,7 +174,6 @@ public: int propType; // When !NotFullyResolved const char *propTypeName; // When NotFullyResolved }; - int coreIndex; union { // The notify index is in the range returned by QObjectPrivate::signalIndex(). // This is different from QMetaMethod::methodIndex(). @@ -208,6 +207,7 @@ public: qintptr accessorData; }; }; + int coreIndex; private: friend class QQmlPropertyData; diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index d713e9ee03..408f17ffde 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -81,7 +81,7 @@ #define ASSERT_MAINTHREAD() do { if (m_thread->isThisThread()) qFatal("QQmlTypeLoader: Caller not in main thread"); } while (false) #define ASSERT_LOADTHREAD() do { if (!m_thread->isThisThread()) qFatal("QQmlTypeLoader: Caller not in load thread"); } while (false) -#define ASSERT_CALLBACK() do { if(!m_manager || !m_manager->m_thread->isThisThread()) qFatal("QQmlDataBlob: An API call was made outside a callback"); } while(false) +#define ASSERT_CALLBACK() do { if (!m_typeLoader || !m_typeLoader->m_thread->isThisThread()) qFatal("QQmlDataBlob: An API call was made outside a callback"); } while (false) #else @@ -1612,6 +1612,20 @@ QQmlTypeData *QQmlTypeLoader::getType(const QUrl &url, Mode mode) } else { QQmlTypeLoader::load(typeData, mode); } + } else if ((mode == PreferSynchronous) && QQmlFile::isSynchronous(url)) { + // this was started Asynchronous, but we need to force Synchronous + // completion now (if at all possible with this type of URL). + + if (!m_thread->isThisThread()) { + // this only works when called directly from the UI thread, but not + // when recursively called on the QML thread via resolveTypes() + + while (!typeData->isCompleteOrError()) { + unlock(); + m_thread->waitForNextMessage(); + lock(); + } + } } typeData->addref(); @@ -2114,6 +2128,7 @@ void QQmlTypeData::dataReceived(const Data &data) QmlIR::IRBuilder compiler(QV8Engine::get(qmlEngine)->illegalNames()); if (!compiler.generateFromQml(code, finalUrlString(), m_document.data())) { QList<QQmlError> errors; + errors.reserve(compiler.errors.count()); foreach (const QQmlJS::DiagnosticMessage &msg, compiler.errors) { QQmlError e; e.setUrl(finalUrl()); @@ -2519,8 +2534,8 @@ QV4::PersistentValue QQmlScriptData::scriptValueForContext(QQmlContextData *pare return QV4::PersistentValue(); } - QV4::ScopedValue qmlglobal(scope, QV4::QmlContextWrapper::qmlScope(v4, ctxt, 0)); - QV4::QmlContextWrapper::takeContextOwnership(qmlglobal); + QV4::Scoped<QV4::QmlContextWrapper> qmlglobal(scope, QV4::QmlContextWrapper::qmlScope(v4, ctxt, 0)); + qmlglobal->takeContextOwnership(); m_program->qml.set(scope.engine, qmlglobal); m_program->run(); @@ -2594,7 +2609,7 @@ void QQmlScriptBlob::dataReceived(const Data &data) return; } if (!unit) { - unit.take(new EmptyCompilationUnit); + unit.adopt(new EmptyCompilationUnit); } irUnit.javaScriptCompilationUnit = unit; irUnit.imports = collector.imports; diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index d9ea273698..5be478fa65 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -60,7 +60,7 @@ #include <private/qflagpointer_p.h> #include <private/qqmlirbuilder_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4script_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp index d0658f2c3c..23cc12c895 100644 --- a/src/qml/qml/qqmltypenamecache.cpp +++ b/src/qml/qml/qqmltypenamecache.cpp @@ -125,7 +125,7 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, cons const Import *i = static_cast<const Import *>(importNamespace); Q_ASSERT(i->scriptIndex == -1); - QMap<const Import *, QStringHash<Import> >::const_iterator it = m_namespacedImports.find(i); + QMap<const Import *, QStringHash<Import> >::const_iterator it = m_namespacedImports.constFind(i); if (it != m_namespacedImports.constEnd()) { Result r = query(*it, name); if (r.isValid()) diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 8a2118ef27..1d72b2da0d 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -124,19 +124,19 @@ ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, Q } -ReturnedValue QmlTypeWrapper::get(Managed *m, String *name, bool *hasProperty) +ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<QmlTypeWrapper>()); - QV4::ExecutionEngine *v4 = static_cast<QmlTypeWrapper *>(m)->engine(); + QV4::ExecutionEngine *v4 = static_cast<const QmlTypeWrapper *>(m)->engine(); QV4::Scope scope(v4); - Scoped<QmlTypeWrapper> w(scope, static_cast<QmlTypeWrapper *>(m)); + Scoped<QmlTypeWrapper> w(scope, static_cast<const QmlTypeWrapper *>(m)); if (hasProperty) *hasProperty = true; - QQmlContextData *context = v4->v8Engine->callingContext(); + QQmlContextData *context = v4->callingQmlContext(); QObject *object = w->d()->object; @@ -240,7 +240,7 @@ void QmlTypeWrapper::put(Managed *m, String *name, const Value &value) return; QV4::Scope scope(v4); - QQmlContextData *context = v4->v8Engine->callingContext(); + QQmlContextData *context = v4->callingQmlContext(); QQmlType *type = w->d()->type; if (type && !type->isSingleton() && w->d()->object) { diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h index 660d2836ff..14741a5bad 100644 --- a/src/qml/qml/qqmltypewrapper_p.h +++ b/src/qml/qml/qqmltypewrapper_p.h @@ -48,7 +48,7 @@ #include <QtCore/qglobal.h> #include <QtCore/qpointer.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4object_p.h> QT_BEGIN_NAMESPACE @@ -94,7 +94,7 @@ struct Q_QML_EXPORT QmlTypeWrapper : Object Heap::QmlTypeWrapper::TypeNameMode = Heap::QmlTypeWrapper::IncludeEnums); - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); static void put(Managed *m, String *name, const Value &value); static PropertyAttributes query(const Managed *, String *name); static bool isEqualTo(Managed *that, Managed *o); diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp index 10eaae0c77..6a71a07e9b 100644 --- a/src/qml/qml/qqmlvaluetype.cpp +++ b/src/qml/qml/qqmlvaluetype.cpp @@ -517,7 +517,9 @@ void QQmlEasingValueType::setBezierCurve(const QVariantList &customCurveVariant) if ((variantList.count() % 6) == 0) { bool allRealsOk = true; QList<qreal> reals; - for (int i = 0; i < variantList.count(); i++) { + const int variantListCount = variantList.count(); + reals.reserve(variantListCount); + for (int i = 0; i < variantListCount; i++) { bool ok; const qreal real = variantList.at(i).toReal(&ok); reals.append(real); diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h index 2c02cc0aa1..abd73d7f35 100644 --- a/src/qml/qml/qqmlvaluetype_p.h +++ b/src/qml/qml/qqmlvaluetype_p.h @@ -209,7 +209,6 @@ struct QQmlEasingValueType { QEasingCurve v; Q_GADGET - Q_ENUMS(Type) Q_PROPERTY(QQmlEasingValueType::Type type READ type WRITE setType FINAL) Q_PROPERTY(qreal amplitude READ amplitude WRITE setAmplitude FINAL) @@ -243,6 +242,7 @@ public: SineCurve = QEasingCurve::SineCurve, CosineCurve = QEasingCurve::CosineCurve, Bezier = QEasingCurve::BezierSpline }; + Q_ENUM(Type) Type type() const; qreal amplitude() const; diff --git a/src/qml/qml/qqmlvaluetypeproxybinding.cpp b/src/qml/qml/qqmlvaluetypeproxybinding.cpp index cfc9b196d2..3bc8493cbb 100644 --- a/src/qml/qml/qqmlvaluetypeproxybinding.cpp +++ b/src/qml/qml/qqmlvaluetypeproxybinding.cpp @@ -35,80 +35,42 @@ QT_BEGIN_NAMESPACE -// Used in qqmlabstractbinding.cpp -QQmlAbstractBinding::VTable QQmlValueTypeProxyBinding_vtable = { - QQmlAbstractBinding::default_destroy<QQmlValueTypeProxyBinding>, - QQmlAbstractBinding::default_expression, - QQmlValueTypeProxyBinding::propertyIndex, - QQmlValueTypeProxyBinding::object, - QQmlValueTypeProxyBinding::setEnabled, - QQmlValueTypeProxyBinding::update, - QQmlAbstractBinding::default_retargetBinding -}; - QQmlValueTypeProxyBinding::QQmlValueTypeProxyBinding(QObject *o, int index) -: QQmlAbstractBinding(ValueTypeProxy), m_object(o), m_index(index), m_bindings(0) + : QQmlAbstractBinding(), + m_bindings(0) { + m_target = o; + m_targetIndex = index; } QQmlValueTypeProxyBinding::~QQmlValueTypeProxyBinding() { - QQmlAbstractBinding *binding = m_bindings; - // This must be identical to the logic in QQmlData::destroyed() + QQmlAbstractBinding *binding = m_bindings.data(); while (binding) { - QQmlAbstractBinding *next = binding->nextBinding(); binding->setAddedToObject(false); - binding->setNextBinding(0); - binding->destroy(); - binding = next; + binding = binding->nextBinding(); } } -void QQmlValueTypeProxyBinding::setEnabled(QQmlAbstractBinding *_This, - bool e, QQmlPropertyPrivate::WriteFlags flags) +void QQmlValueTypeProxyBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags) { - QQmlValueTypeProxyBinding *This = static_cast<QQmlValueTypeProxyBinding *>(_This); - - if (e) { - QQmlAbstractBinding *bindings = This->m_bindings; - This->recursiveEnable(bindings, flags); - } else { - QQmlAbstractBinding *bindings = This->m_bindings; - This->recursiveDisable(bindings); + QQmlAbstractBinding *b = m_bindings.data(); + while (b) { + b->setEnabled(e, flags); + b = b->nextBinding(); } } -void QQmlValueTypeProxyBinding::recursiveEnable(QQmlAbstractBinding *b, QQmlPropertyPrivate::WriteFlags flags) -{ - if (!b) - return; - - recursiveEnable(b->nextBinding(), flags); - - if (b) - b->setEnabled(true, flags); -} - -void QQmlValueTypeProxyBinding::recursiveDisable(QQmlAbstractBinding *b) -{ - if (!b) - return; - - recursiveDisable(b->nextBinding()); - - if (b) - b->setEnabled(false, 0); -} - -void QQmlValueTypeProxyBinding::update(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags) +bool QQmlValueTypeProxyBinding::isValueTypeProxy() const { + return true; } QQmlAbstractBinding *QQmlValueTypeProxyBinding::binding(int propertyIndex) { - QQmlAbstractBinding *binding = m_bindings; + QQmlAbstractBinding *binding = m_bindings.data(); - while (binding && binding->propertyIndex() != propertyIndex) + while (binding && binding->targetPropertyIndex() != propertyIndex) binding = binding->nextBinding(); return binding; @@ -119,23 +81,20 @@ Removes a collection of bindings, corresponding to the set bits in \a mask. */ void QQmlValueTypeProxyBinding::removeBindings(quint32 mask) { - QQmlAbstractBinding *binding = m_bindings; + QQmlAbstractBinding *binding = m_bindings.data(); QQmlAbstractBinding *lastBinding = 0; while (binding) { - int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(binding->propertyIndex()); + int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(binding->targetPropertyIndex()); if (valueTypeIndex != -1 && (mask & (1 << valueTypeIndex))) { QQmlAbstractBinding *remove = binding; + remove->setAddedToObject(false); binding = remove->nextBinding(); if (lastBinding == 0) m_bindings = remove->nextBinding(); else lastBinding->setNextBinding(remove->nextBinding()); - - remove->setAddedToObject(false); - remove->setNextBinding(0); - remove->destroy(); } else { lastBinding = binding; binding = binding->nextBinding(); @@ -143,24 +102,4 @@ void QQmlValueTypeProxyBinding::removeBindings(quint32 mask) } } -int QQmlValueTypeProxyBinding::propertyIndex(const QQmlAbstractBinding *This) -{ - return static_cast<const QQmlValueTypeProxyBinding *>(This)->m_index; -} - -QObject *QQmlValueTypeProxyBinding::object(const QQmlAbstractBinding *This) -{ - return static_cast<const QQmlValueTypeProxyBinding *>(This)->m_object; -} - -int QQmlValueTypeProxyBinding::propertyIndex() const -{ - return m_index; -} - -QObject *QQmlValueTypeProxyBinding::object() const -{ - return m_object; -} - QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlvaluetypeproxybinding_p.h b/src/qml/qml/qqmlvaluetypeproxybinding_p.h index 873fbb4af1..4afadfc17d 100644 --- a/src/qml/qml/qqmlvaluetypeproxybinding_p.h +++ b/src/qml/qml/qqmlvaluetypeproxybinding_p.h @@ -54,30 +54,18 @@ class QQmlValueTypeProxyBinding : public QQmlAbstractBinding public: QQmlValueTypeProxyBinding(QObject *o, int coreIndex); - int propertyIndex() const; - QObject *object() const; - - QQmlAbstractBinding *binding(int propertyIndex); - + QQmlAbstractBinding *binding(int targetPropertyIndex); void removeBindings(quint32 mask); - // "Inherited" from QQmlAbstractBinding - static void setEnabled(QQmlAbstractBinding *, bool, QQmlPropertyPrivate::WriteFlags); - static void update(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags); - static int propertyIndex(const QQmlAbstractBinding *); - static QObject *object(const QQmlAbstractBinding *); + virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags); + virtual bool isValueTypeProxy() const; protected: ~QQmlValueTypeProxyBinding(); private: - void recursiveEnable(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags); - void recursiveDisable(QQmlAbstractBinding *); - friend class QQmlAbstractBinding; - QObject *m_object; - int m_index; - QQmlAbstractBinding *m_bindings; + Ptr m_bindings; }; QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index e87d9ede77..b0ab85199d 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -43,7 +43,6 @@ #include <private/qv4engine_p.h> #include <private/qv4functionobject_p.h> #include <private/qv4variantobject_p.h> -#include <private/qv4qmlextensions_p.h> #include <private/qv4alloca_p.h> QT_BEGIN_NAMESPACE @@ -165,13 +164,13 @@ bool QQmlValueTypeReference::readReferenceValue() const void QQmlValueTypeWrapper::initProto(ExecutionEngine *v4) { - if (v4->qmlExtensions()->valueTypeWrapperPrototype) + if (v4->valueTypeWrapperPrototype()->as<Object>()) return; Scope scope(v4); ScopedObject o(scope, v4->newObject()); - o->defineDefaultProperty(v4->id_toString, method_toString, 1); - v4->qmlExtensions()->valueTypeWrapperPrototype = o->d(); + o->defineDefaultProperty(v4->id_toString(), method_toString, 1); + v4->jsObjects[QV4::ExecutionEngine::ValueTypeProto] = o->d(); } ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, QObject *object, int property, const QMetaObject *metaObject, int typeId) @@ -180,7 +179,7 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, QObject *obj initProto(engine); Scoped<QQmlValueTypeReference> r(scope, engine->memoryManager->alloc<QQmlValueTypeReference>(engine)); - ScopedObject proto(scope, engine->qmlExtensions()->valueTypeWrapperPrototype); + ScopedObject proto(scope, engine->valueTypeWrapperPrototype()); r->setPrototype(proto); r->d()->object = object; r->d()->property = property; r->d()->propertyCache = QJSEnginePrivate::get(engine)->cache(metaObject); @@ -195,7 +194,7 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, const QVaria initProto(engine); Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->alloc<QQmlValueTypeWrapper>(engine)); - ScopedObject proto(scope, engine->qmlExtensions()->valueTypeWrapperPrototype); + ScopedObject proto(scope, engine->valueTypeWrapperPrototype()); r->setPrototype(proto); r->d()->propertyCache = QJSEnginePrivate::get(engine)->cache(metaObject); r->d()->valueType = QQmlValueTypeFactory::valueType(typeId); @@ -292,7 +291,7 @@ bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const ReturnedValue QQmlValueTypeWrapper::method_toString(CallContext *ctx) { - Object *o = ctx->thisObject().asObject(); + Object *o = ctx->thisObject().as<Object>(); if (!o) return ctx->engine()->throwTypeError(); QQmlValueTypeWrapper *w = o->as<QQmlValueTypeWrapper>(); @@ -327,14 +326,14 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(CallContext *ctx) return Encode(ctx->engine()->newString(result)); } -ReturnedValue QQmlValueTypeWrapper::get(Managed *m, String *name, bool *hasProperty) +ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<QQmlValueTypeWrapper>()); - QQmlValueTypeWrapper *r = static_cast<QQmlValueTypeWrapper *>(m); + const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m); QV4::ExecutionEngine *v4 = r->engine(); // Note: readReferenceValue() can change the reference->type. - if (QQmlValueTypeReference *reference = r->as<QQmlValueTypeReference>()) { + if (const QQmlValueTypeReference *reference = r->as<QQmlValueTypeReference>()) { if (!reference->readReferenceValue()) return Primitive::undefinedValue().asReturnedValue(); } @@ -410,45 +409,41 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) QMetaProperty property = metaObject->property(pd->coreIndex); Q_ASSERT(property.isValid()); - QQmlBinding *newBinding = 0; - - QV4::ScopedFunctionObject f(scope, value); - if (reference && f) { - if (!f->isBinding()) { - // assigning a JS function to a non-var-property is not allowed. - QString error = QStringLiteral("Cannot assign JavaScript function to value-type property"); - ScopedString e(scope, v4->newString(error)); - v4->throwError(e); - return; - } + if (reference) { + QV4::ScopedFunctionObject f(scope, value); + if (f) { + if (!f->isBinding()) { + // assigning a JS function to a non-var-property is not allowed. + QString error = QStringLiteral("Cannot assign JavaScript function to value-type property"); + ScopedString e(scope, v4->newString(error)); + v4->throwError(e); + return; + } - QQmlContextData *context = QmlContextWrapper::callingContext(v4); + QQmlContextData *context = v4->callingQmlContext(); - QQmlPropertyData cacheData; - cacheData.setFlags(QQmlPropertyData::IsWritable | - QQmlPropertyData::IsValueTypeVirtual); - cacheData.propType = writeBackPropertyType; - cacheData.coreIndex = reference->d()->property; - cacheData.valueTypeFlags = 0; - cacheData.valueTypeCoreIndex = pd->coreIndex; - cacheData.valueTypePropType = property.userType(); + QQmlPropertyData cacheData; + cacheData.setFlags(QQmlPropertyData::IsWritable | + QQmlPropertyData::IsValueTypeVirtual); + cacheData.propType = writeBackPropertyType; + cacheData.coreIndex = reference->d()->property; + cacheData.valueTypeFlags = 0; + cacheData.valueTypeCoreIndex = pd->coreIndex; + cacheData.valueTypePropType = property.userType(); - QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f); - bindingFunction->initBindingLocation(); + QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f); + bindingFunction->initBindingLocation(); - newBinding = new QQmlBinding(value, reference->d()->object, context); - newBinding->setTarget(reference->d()->object, cacheData, context); - } + QQmlBinding *newBinding = new QQmlBinding(value, reference->d()->object, context); + newBinding->setTarget(reference->d()->object, cacheData); + QQmlPropertyPrivate::setBinding(newBinding); + return; + } else { + QQmlPropertyPrivate::removeBinding(reference->d()->object, QQmlPropertyData::encodeValueTypePropertyIndex(reference->d()->property, pd->coreIndex)); - if (reference) { - QQmlAbstractBinding *oldBinding = - QQmlPropertyPrivate::setBinding(reference->d()->object, reference->d()->property, pd->coreIndex, newBinding); - if (oldBinding) - oldBinding->destroy(); + } } - if (newBinding) - return; QVariant v = v4->toVariant(value, property.userType()); diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h index cad48e661c..5f0edfb71d 100644 --- a/src/qml/qml/qqmlvaluetypewrapper_p.h +++ b/src/qml/qml/qqmlvaluetypewrapper_p.h @@ -48,7 +48,7 @@ #include <QtCore/qglobal.h> #include <private/qtqmlglobal_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4object_p.h> QT_BEGIN_NAMESPACE @@ -89,7 +89,7 @@ public: int typeId() const; bool write(QObject *target, int propertyIndex) const; - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); static void put(Managed *m, String *name, const Value &value); static bool isEqualTo(Managed *m, Managed *other); static PropertyAttributes query(const Managed *, String *name); diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 97fc382c33..9f02c905fc 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -104,13 +104,11 @@ public: inline double asDouble(); inline const QString &asQString(); inline const QUrl &asQUrl(); - inline const QTime &asQTime(); inline const QDate &asQDate(); inline const QDateTime &asQDateTime(); inline const QRectF &asQRectF(); inline const QPointF &asQPointF(); inline const QSizeF &asQSizeF(); - inline const QJSValue &asQJSValue(); inline void setValue(QObject *v, QQmlVMEMetaObject *target, int index); inline void setValue(const QVariant &); @@ -125,9 +123,6 @@ public: inline void setValue(const QRectF &); inline void setValue(const QPointF &); inline void setValue(const QSizeF &); - inline void setValue(const QJSValue &); - - inline void setDataType(int t); inline void ensureValueType(int); @@ -196,9 +191,6 @@ void QQmlVMEVariant::cleanup() } else if (type == qMetaTypeId<QVariant>()) { ((QVariant *)dataPtr())->~QVariant(); type = QVariant::Invalid; - } else if (type == qMetaTypeId<QJSValue>()) { - ((QJSValue *)dataPtr())->~QJSValue(); - type = QVariant::Invalid; } else { if (QQml_valueTypeProvider()->destroyValueType(type, dataPtr(), dataSize())) { type = QVariant::Invalid; @@ -282,14 +274,6 @@ const QUrl &QQmlVMEVariant::asQUrl() return *(QUrl *)(dataPtr()); } -const QTime &QQmlVMEVariant::asQTime() -{ - if (type != QMetaType::QTime) - setValue(QTime()); - - return *(QTime *)(dataPtr()); -} - const QDate &QQmlVMEVariant::asQDate() { if (type != QMetaType::QDate) @@ -330,14 +314,6 @@ const QPointF &QQmlVMEVariant::asQPointF() return *(QPointF *)(dataPtr()); } -const QJSValue &QQmlVMEVariant::asQJSValue() -{ - if (type != qMetaTypeId<QJSValue>()) - setValue(QJSValue()); - - return *(QJSValue *)(dataPtr()); -} - void QQmlVMEVariant::setValue(QObject *v, QQmlVMEMetaObject *target, int index) { if (type != QMetaType::QObjectStar) { @@ -474,22 +450,6 @@ void QQmlVMEVariant::setValue(const QSizeF &v) } } -void QQmlVMEVariant::setValue(const QJSValue &v) -{ - if (type != qMetaTypeId<QJSValue>()) { - cleanup(); - type = qMetaTypeId<QJSValue>(); - new (dataPtr()) QJSValue(v); - } else { - *(QJSValue *)(dataPtr()) = v; - } -} - -void QQmlVMEVariant::setDataType(int t) -{ - type = t; -} - void QQmlVMEVariant::ensureValueType(int t) { if (type != t) { @@ -500,8 +460,8 @@ void QQmlVMEVariant::ensureValueType(int t) } QQmlVMEMetaObjectEndpoint::QQmlVMEMetaObjectEndpoint() + : QQmlNotifierEndpoint(QQmlNotifierEndpoint::QQmlVMEMetaObjectEndpoint) { - setCallback(QQmlNotifierEndpoint::QQmlVMEMetaObjectEndpoint); } void QQmlVMEMetaObjectEndpoint_callback(QQmlNotifierEndpoint *e, void **) @@ -874,10 +834,8 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) int flags = *reinterpret_cast<int*>(a[3]); if (flags & QQmlPropertyPrivate::RemoveBindingOnAliasWrite) { QQmlData *targetData = QQmlData::get(target); - if (targetData && targetData->hasBindingBit(d->propertyIndex())) { - QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(target, d->propertyIndex(), d->isValueTypeAlias()?d->valueTypeIndex():-1, 0); - if (binding) binding->destroy(); - } + if (targetData && targetData->hasBindingBit(d->propertyIndex())) + QQmlPropertyPrivate::removeBinding(target, d->propertyIdx); } } @@ -1183,7 +1141,7 @@ void QQmlVMEMetaObject::setVmeMethod(int index, const QV4::Value &function) v8methods = new QV4::PersistentValue[metaData->methodCount]; int methodIndex = index - methodOffset() - plainSignals; - v8methods[methodIndex].set(function.asObject()->engine(), function); + v8methods[methodIndex].set(function.as<QV4::Object>()->engine(), function); } QV4::ReturnedValue QQmlVMEMetaObject::vmeProperty(int index) @@ -1220,8 +1178,9 @@ bool QQmlVMEMetaObject::ensureVarPropertiesAllocated() void QQmlVMEMetaObject::ensureQObjectWrapper() { - QQmlEnginePrivate *ep = (ctxt == 0 || ctxt->engine == 0) ? 0 : QQmlEnginePrivate::get(ctxt->engine); - QV4::ExecutionEngine *v4 = (ep == 0) ? 0 : ep->v4engine(); + Q_ASSERT(ctxt && ctxt->engine); + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(ctxt->engine); + QV4::ExecutionEngine *v4 = ep->v4engine(); QV4::QObjectWrapper::wrap(v4, object); } @@ -1251,7 +1210,7 @@ void QQmlVMEMetaObject::mark(QV4::ExecutionEngine *e) void QQmlVMEMetaObject::allocateVarPropertiesArray() { QQmlEngine *qml = qmlEngine(object); - assert(qml); + Q_ASSERT(qml); QV4::ExecutionEngine *v4 = QV8Engine::getV4(qml->handle()); QV4::Scope scope(v4); varProperties.set(scope.engine, v4->newArrayObject(metaData->varPropertyCount)); diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h index f3048d426a..a320163f23 100644 --- a/src/qml/qml/qqmlvmemetaobject_p.h +++ b/src/qml/qml/qqmlvmemetaobject_p.h @@ -63,7 +63,7 @@ #include <private/qv8engine_p.h> #include <private/qflagpointer_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/qml/qqmlwatcher.cpp b/src/qml/qml/qqmlwatcher.cpp deleted file mode 100644 index 9726b6f3b9..0000000000 --- a/src/qml/qml/qqmlwatcher.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/**************************************************************************** -** -** 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 "qqmlwatcher_p.h" - -#include "qqmlexpression.h" -#include "qqmlcontext.h" -#include "qqml.h" - -#include <private/qqmldebugservice_p.h> -#include "qqmlproperty_p.h" -#include "qqmlvaluetype_p.h" - -#include <QtCore/qmetaobject.h> -#include <QtCore/qdebug.h> - -QT_BEGIN_NAMESPACE - - -class QQmlWatchProxy : public QObject -{ - Q_OBJECT -public: - QQmlWatchProxy(int id, - QObject *object, - int debugId, - const QMetaProperty &prop, - QQmlWatcher *parent = 0); - - QQmlWatchProxy(int id, - QQmlExpression *exp, - int debugId, - QQmlWatcher *parent = 0); - -public slots: - void notifyValueChanged(); - -private: - friend class QQmlWatcher; - int m_id; - QQmlWatcher *m_watch; - QObject *m_object; - int m_debugId; - QMetaProperty m_property; - - QQmlExpression *m_expr; -}; - -QQmlWatchProxy::QQmlWatchProxy(int id, - QQmlExpression *exp, - int debugId, - QQmlWatcher *parent) -: QObject(parent), m_id(id), m_watch(parent), m_object(0), m_debugId(debugId), m_expr(exp) -{ - QObject::connect(m_expr, SIGNAL(valueChanged()), this, SLOT(notifyValueChanged())); -} - -QQmlWatchProxy::QQmlWatchProxy(int id, - QObject *object, - int debugId, - const QMetaProperty &prop, - QQmlWatcher *parent) -: QObject(parent), m_id(id), m_watch(parent), m_object(object), m_debugId(debugId), m_property(prop), m_expr(0) -{ - static int refreshIdx = -1; - if(refreshIdx == -1) - refreshIdx = QQmlWatchProxy::staticMetaObject.indexOfMethod("notifyValueChanged()"); - - if (prop.hasNotifySignal()) - QQmlPropertyPrivate::connect(m_object, prop.notifySignalIndex(), this, refreshIdx); -} - -void QQmlWatchProxy::notifyValueChanged() -{ - QVariant v; - if (m_expr) - v = m_expr->evaluate(); - else if (QQmlValueTypeFactory::isValueType(m_property.userType())) - v = m_property.read(m_object); - - emit m_watch->propertyChanged(m_id, m_debugId, m_property, v); -} - - -QQmlWatcher::QQmlWatcher(QObject *parent) - : QObject(parent) -{ -} - -bool QQmlWatcher::addWatch(int id, quint32 debugId) -{ - QObject *object = QQmlDebugService::objectForId(debugId); - if (object) { - int propCount = object->metaObject()->propertyCount(); - for (int ii=0; ii<propCount; ii++) - addPropertyWatch(id, object, debugId, object->metaObject()->property(ii)); - return true; - } - return false; -} - -bool QQmlWatcher::addWatch(int id, quint32 debugId, const QByteArray &property) -{ - QObject *object = QQmlDebugService::objectForId(debugId); - if (object) { - int index = object->metaObject()->indexOfProperty(property.constData()); - if (index >= 0) { - addPropertyWatch(id, object, debugId, object->metaObject()->property(index)); - return true; - } - } - return false; -} - -bool QQmlWatcher::addWatch(int id, quint32 objectId, const QString &expr) -{ - QObject *object = QQmlDebugService::objectForId(objectId); - QQmlContext *context = qmlContext(object); - if (context) { - QQmlExpression *exprObj = new QQmlExpression(context, object, expr); - exprObj->setNotifyOnValueChanged(true); - QQmlWatchProxy *proxy = new QQmlWatchProxy(id, exprObj, objectId, this); - exprObj->setParent(proxy); - m_proxies[id].append(proxy); - proxy->notifyValueChanged(); - return true; - } - return false; -} - -bool QQmlWatcher::removeWatch(int id) -{ - if (!m_proxies.contains(id)) - return false; - - QList<QPointer<QQmlWatchProxy> > proxies = m_proxies.take(id); - qDeleteAll(proxies); - return true; -} - -void QQmlWatcher::addPropertyWatch(int id, QObject *object, quint32 debugId, const QMetaProperty &property) -{ - QQmlWatchProxy *proxy = new QQmlWatchProxy(id, object, debugId, property, this); - m_proxies[id].append(proxy); - - proxy->notifyValueChanged(); -} - -QT_END_NAMESPACE - -#include <qqmlwatcher.moc> diff --git a/src/qml/qml/qqmlwatcher_p.h b/src/qml/qml/qqmlwatcher_p.h deleted file mode 100644 index a7bb3c3418..0000000000 --- a/src/qml/qml/qqmlwatcher_p.h +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************************** -** -** 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 QQMLWATCHER_P_H -#define QQMLWATCHER_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtCore/qobject.h> -#include <QtCore/qlist.h> -#include <QtCore/qpair.h> -#include <QtCore/qhash.h> -#include <QtCore/qset.h> -#include <QtCore/qpointer.h> - -QT_BEGIN_NAMESPACE - -class QQmlWatchProxy; -class QQmlExpression; -class QQmlContext; -class QMetaProperty; - -class QQmlWatcher : public QObject -{ - Q_OBJECT -public: - QQmlWatcher(QObject * = 0); - - bool addWatch(int id, quint32 objectId); - bool addWatch(int id, quint32 objectId, const QByteArray &property); - bool addWatch(int id, quint32 objectId, const QString &expr); - - bool removeWatch(int id); - -Q_SIGNALS: - void propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value); - -private: - friend class QQmlWatchProxy; - void addPropertyWatch(int id, QObject *object, quint32 objectId, const QMetaProperty &property); - - QHash<int, QList<QPointer<QQmlWatchProxy> > > m_proxies; -}; - -QT_END_NAMESPACE - -#endif // QQMLWATCHER_P_H diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index 2a3ede6a22..0edb672517 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -60,6 +60,7 @@ #include <private/qv4objectproto_p.h> #include <private/qv4scopedvalue_p.h> #include <private/qv4arraybuffer_p.h> +#include <private/qv4jsonobject_p.h> using namespace QV4; @@ -99,7 +100,7 @@ static ReturnedValue constructMeObject(const Value &thisObj, ExecutionEngine *v4 Scope scope(v4); ScopedObject meObj(scope, v4->newObject()); meObj->put(ScopedString(scope, v4->newString(QStringLiteral("ThisObject"))), thisObj); - ScopedValue v(scope, QmlContextWrapper::qmlScope(v4, v4->v8Engine->callingContext(), 0)); + ScopedValue v(scope, QmlContextWrapper::qmlScope(v4, v4->callingQmlContext(), 0)); meObj->put(ScopedString(scope, v4->newString(QStringLiteral("ActivationObject"))), v); return meObj.asReturnedValue(); } @@ -222,8 +223,8 @@ public: static ReturnedValue create(ExecutionEngine *, NodeImpl *, const QList<NodeImpl *> &); // JS API - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); + static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); }; Heap::NamedNodeMap::NamedNodeMap(ExecutionEngine *engine, NodeImpl *data, const QList<NodeImpl *> &list) @@ -244,8 +245,8 @@ public: V4_NEEDS_DESTROY // JS API - static ReturnedValue get(Managed *m, String *name, bool *hasProperty); - static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); + static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); // C++ API static ReturnedValue create(ExecutionEngine *, NodeImpl *); @@ -273,6 +274,7 @@ public: static ReturnedValue method_get_nodeName(CallContext *ctx); static ReturnedValue method_get_nodeValue(CallContext *ctx); static ReturnedValue method_get_nodeType(CallContext *ctx); + static ReturnedValue method_get_namespaceUri(CallContext *ctx); static ReturnedValue method_get_parentNode(CallContext *ctx); static ReturnedValue method_get_childNodes(CallContext *ctx); @@ -302,6 +304,7 @@ Heap::NodePrototype::NodePrototype(ExecutionEngine *engine) o->defineAccessorProperty(QStringLiteral("nodeName"), QV4::NodePrototype::method_get_nodeName, 0); o->defineAccessorProperty(QStringLiteral("nodeValue"), QV4::NodePrototype::method_get_nodeValue, 0); o->defineAccessorProperty(QStringLiteral("nodeType"), QV4::NodePrototype::method_get_nodeType, 0); + o->defineAccessorProperty(QStringLiteral("namespaceUri"), QV4::NodePrototype::method_get_namespaceUri, 0); o->defineAccessorProperty(QStringLiteral("parentNode"), QV4::NodePrototype::method_get_parentNode, 0); o->defineAccessorProperty(QStringLiteral("childNodes"), QV4::NodePrototype::method_get_childNodes, 0); @@ -470,6 +473,16 @@ ReturnedValue NodePrototype::method_get_nodeType(CallContext *ctx) return Encode(r->d()->d->type); } +ReturnedValue NodePrototype::method_get_namespaceUri(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + if (!r) + return ctx->engine()->throwTypeError(); + + return Encode(ctx->d()->engine->newString(r->d()->d->namespaceUri)); +} + ReturnedValue NodePrototype::method_get_parentNode(CallContext *ctx) { Scope scope(ctx); @@ -871,10 +884,10 @@ bool Node::isNull() const return d()->d == 0; } -ReturnedValue NamedNodeMap::getIndexed(Managed *m, uint index, bool *hasProperty) +ReturnedValue NamedNodeMap::getIndexed(const Managed *m, uint index, bool *hasProperty) { Q_ASSERT(m->as<NamedNodeMap>()); - NamedNodeMap *r = static_cast<NamedNodeMap *>(m); + const NamedNodeMap *r = static_cast<const NamedNodeMap *>(m); QV4::ExecutionEngine *v4 = r->engine(); if ((int)index < r->d()->list.count()) { @@ -887,14 +900,14 @@ ReturnedValue NamedNodeMap::getIndexed(Managed *m, uint index, bool *hasProperty return Encode::undefined(); } -ReturnedValue NamedNodeMap::get(Managed *m, String *name, bool *hasProperty) +ReturnedValue NamedNodeMap::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<NamedNodeMap>()); - NamedNodeMap *r = static_cast<NamedNodeMap *>(m); + const NamedNodeMap *r = static_cast<const NamedNodeMap *>(m); QV4::ExecutionEngine *v4 = r->engine(); name->makeIdentifier(v4); - if (name->equals(v4->id_length)) + if (name->equals(v4->id_length())) return Primitive::fromInt32(r->d()->list.count()).asReturnedValue(); QString str = name->toQString(); @@ -916,10 +929,10 @@ ReturnedValue NamedNodeMap::create(ExecutionEngine *v4, NodeImpl *data, const QL return (v4->memoryManager->alloc<NamedNodeMap>(v4, data, list))->asReturnedValue(); } -ReturnedValue NodeList::getIndexed(Managed *m, uint index, bool *hasProperty) +ReturnedValue NodeList::getIndexed(const Managed *m, uint index, bool *hasProperty) { Q_ASSERT(m->as<NodeList>()); - NodeList *r = static_cast<NodeList *>(m); + const NodeList *r = static_cast<const NodeList *>(m); QV4::ExecutionEngine *v4 = r->engine(); if ((int)index < r->d()->d->children.count()) { @@ -932,15 +945,15 @@ ReturnedValue NodeList::getIndexed(Managed *m, uint index, bool *hasProperty) return Encode::undefined(); } -ReturnedValue NodeList::get(Managed *m, String *name, bool *hasProperty) +ReturnedValue NodeList::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<NodeList>()); - NodeList *r = static_cast<NodeList *>(m); + const NodeList *r = static_cast<const NodeList *>(m); QV4::ExecutionEngine *v4 = r->engine(); name->makeIdentifier(v4); - if (name->equals(v4->id_length)) + if (name->equals(v4->id_length())) return Primitive::fromInt32(r->d()->d->children.count()).asReturnedValue(); return Object::get(m, name, hasProperty); } @@ -1019,13 +1032,15 @@ public: QString header(const QString &name); QString headers(); - QString responseBody(); const QByteArray & rawResponseBody() const; bool receivedXml() const; const QString & responseType() const; void setResponseType(const QString &); + + QV4::ReturnedValue jsonResponseBody(QV4::ExecutionEngine*); + QV4::ReturnedValue xmlResponseBody(QV4::ExecutionEngine*); private slots: void readyRead(); void error(QNetworkReply::NetworkError); @@ -1076,6 +1091,7 @@ private: QNetworkAccessManager *networkAccessManager() { return m_nam; } QString m_responseType; + QV4::PersistentValue m_parsedDocument; }; QQmlXMLHttpRequest::QQmlXMLHttpRequest(ExecutionEngine *engine, QNetworkAccessManager *manager) @@ -1083,6 +1099,7 @@ QQmlXMLHttpRequest::QQmlXMLHttpRequest(ExecutionEngine *engine, QNetworkAccessMa , m_state(Unsent), m_errorFlag(false), m_sendFlag(false) , m_redirectCount(0), m_gotXml(false), m_textCodec(0), m_network(0), m_nam(manager) , m_responseType() + , m_parsedDocument() { } @@ -1233,11 +1250,12 @@ void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url) m_network = networkAccessManager()->put(request, m_data); } else if (m_method == QLatin1String("DELETE")) { m_network = networkAccessManager()->deleteResource(request); - } else if (m_method == QLatin1String("OPTIONS")) { + } else if ((m_method == QLatin1String("OPTIONS")) || + m_method == QLatin1String("PROPFIND")) { QBuffer *buffer = new QBuffer; buffer->setData(m_data); buffer->open(QIODevice::ReadOnly); - m_network = networkAccessManager()->sendCustomRequest(request, QByteArrayLiteral("OPTIONS"), buffer); + m_network = networkAccessManager()->sendCustomRequest(request, QByteArray(m_method.toUtf8().constData()), buffer); buffer->setParent(m_network); } @@ -1478,6 +1496,32 @@ void QQmlXMLHttpRequest::setResponseType(const QString &responseType) m_responseType = responseType; } +QV4::ReturnedValue QQmlXMLHttpRequest::jsonResponseBody(QV4::ExecutionEngine* engine) +{ + if (m_parsedDocument.isEmpty()) { + Scope scope(engine); + + QJsonParseError error; + const QString& jtext = responseBody(); + JsonParser parser(scope.engine, jtext.constData(), jtext.length()); + ScopedValue jsonObject(scope, parser.parse(&error)); + if (error.error != QJsonParseError::NoError) + return engine->throwSyntaxError(QStringLiteral("JSON.parse: Parse error")); + + m_parsedDocument.set(scope.engine, jsonObject); + } + + return m_parsedDocument.value(); +} + +QV4::ReturnedValue QQmlXMLHttpRequest::xmlResponseBody(QV4::ExecutionEngine* engine) +{ + if (m_parsedDocument.isEmpty()) { + m_parsedDocument.set(engine, Document::load(engine, rawResponseBody())); + } + + return m_parsedDocument.value(); +} #ifndef QT_NO_TEXTCODEC QTextCodec* QQmlXMLHttpRequest::findTextCodec() const @@ -1599,7 +1643,7 @@ struct QQmlXMLHttpRequestWrapper : Object { struct QQmlXMLHttpRequestCtor : FunctionObject { QQmlXMLHttpRequestCtor(ExecutionEngine *engine); - Object *proto; + Pointer<Object> proto; }; } @@ -1625,9 +1669,9 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject c->proto->mark(e); FunctionObject::markObjects(that, e); } - static ReturnedValue construct(Managed *that, QV4::CallData *) + static ReturnedValue construct(const Managed *that, QV4::CallData *) { - Scope scope(static_cast<QQmlXMLHttpRequestCtor *>(that)->engine()); + Scope scope(static_cast<const QQmlXMLHttpRequestCtor *>(that)->engine()); Scoped<QQmlXMLHttpRequestCtor> ctor(scope, that->as<QQmlXMLHttpRequestCtor>()); if (!ctor) return scope.engine->throwTypeError(); @@ -1639,7 +1683,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject return w.asReturnedValue(); } - static ReturnedValue call(Managed *, QV4::CallData *) { + static ReturnedValue call(const Managed *, QV4::CallData *) { return Primitive::undefinedValue().asReturnedValue(); } @@ -1679,7 +1723,7 @@ Heap::QQmlXMLHttpRequestCtor::QQmlXMLHttpRequestCtor(ExecutionEngine *engine) ctor->defineReadonlyProperty(QStringLiteral("DONE"), Primitive::fromInt32(4)); if (!ctor->d()->proto) ctor->setupProto(); - ScopedString s(scope, engine->id_prototype); + ScopedString s(scope, engine->id_prototype()); ctor->defineDefaultProperty(s, ScopedObject(scope, ctor->d()->proto)); } @@ -1739,14 +1783,15 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx) method != QLatin1String("HEAD") && method != QLatin1String("POST") && method != QLatin1String("DELETE") && - method != QLatin1String("OPTIONS")) + method != QLatin1String("OPTIONS") && + method != QLatin1String("PROPFIND")) V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Unsupported HTTP method type"); // Argument 1 - URL QUrl url = QUrl(ctx->args()[1].toQStringNoThrow()); if (url.isRelative()) - url = scope.engine->v8Engine->callingContext()->resolvedUrl(url); + url = scope.engine->callingQmlContext()->resolvedUrl(url); bool async = true; // Argument 2 - async (optional) @@ -1965,7 +2010,9 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseXML(CallContext *ctx) r->readyState() != QQmlXMLHttpRequest::Done)) { return Encode::null(); } else { - return Document::load(scope.engine, r->rawResponseBody()); + if (r->responseType().isEmpty()) + r->setResponseType(QLatin1String("document")); + return r->xmlResponseBody(scope.engine); } } @@ -1986,6 +2033,10 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_get_response(CallContext *ctx) return QV4::Encode(scope.engine->newString(r->responseBody())); } else if (responseType.compare(QLatin1String("arraybuffer"), Qt::CaseInsensitive) == 0) { return QV4::Encode(scope.engine->newArrayBuffer(r->rawResponseBody())); + } else if (responseType.compare(QLatin1String("json"), Qt::CaseInsensitive) == 0) { + return r->jsonResponseBody(scope.engine); + } else if (responseType.compare(QLatin1String("document"), Qt::CaseInsensitive) == 0) { + return r->xmlResponseBody(scope.engine); } else { return QV4::Encode(scope.engine->newString(QString())); } @@ -2033,7 +2084,7 @@ void *qt_add_qmlxmlhttprequest(ExecutionEngine *v4) Scoped<QQmlXMLHttpRequestCtor> ctor(scope, v4->memoryManager->alloc<QQmlXMLHttpRequestCtor>(v4)); ScopedString s(scope, v4->newString(QStringLiteral("XMLHttpRequest"))); - v4->globalObject()->defineReadonlyProperty(s, ctor); + v4->globalObject->defineReadonlyProperty(s, ctor); QQmlXMLHttpRequestData *data = new QQmlXMLHttpRequestData; return data; diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index f53b9a0c7d..ce86fd3923 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -41,7 +41,8 @@ #include <private/qv8engine_p.h> #include <QFileInfo> -#include <private/qqmlprofilerservice_p.h> +#include <private/qqmldebugconnector_p.h> +#include <private/qqmldebugserviceinterfaces_p.h> #include <private/qqmlglobal_p.h> #include <private/qqmlplatform_p.h> @@ -51,6 +52,7 @@ #include <private/qv4include_p.h> #include <private/qv4context_p.h> #include <private/qv4stringobject_p.h> +#include <private/qv4dateobject_p.h> #include <private/qv4mm_p.h> #include <private/qv4jsonobject_p.h> #include <private/qv4objectproto_p.h> @@ -669,7 +671,7 @@ ReturnedValue QtObject::method_formatTime(QV4::CallContext *ctx) QVariant argVariant = ctx->engine()->toVariant(ctx->args()[0], -1); QTime time; - if (ctx->args()[0].asDateObject() || (argVariant.type() == QVariant::String)) + if (ctx->args()[0].as<DateObject>() || (argVariant.type() == QVariant::String)) time = argVariant.toDateTime().time(); else // if (argVariant.type() == QVariant::Time), or invalid. time = argVariant.toTime(); @@ -839,21 +841,21 @@ ReturnedValue QtObject::method_openUrlExternally(QV4::CallContext *ctx) */ ReturnedValue QtObject::method_resolvedUrl(QV4::CallContext *ctx) { - QV8Engine *v8engine = ctx->d()->engine->v8Engine; + ExecutionEngine *v4 = ctx->engine(); - QUrl url = ctx->engine()->toVariant(ctx->args()[0], -1).toUrl(); - QQmlEngine *e = v8engine->engine(); + QUrl url = v4->toVariant(ctx->args()[0], -1).toUrl(); + QQmlEngine *e = v4->qmlEngine(); QQmlEnginePrivate *p = 0; if (e) p = QQmlEnginePrivate::get(e); if (p) { - QQmlContextData *ctxt = v8engine->callingContext(); + QQmlContextData *ctxt = v4->callingQmlContext(); if (ctxt) - return ctx->d()->engine->newString(ctxt->resolvedUrl(url).toString())->asReturnedValue(); + return v4->newString(ctxt->resolvedUrl(url).toString())->asReturnedValue(); else - return ctx->d()->engine->newString(url.toString())->asReturnedValue(); + return v4->newString(url.toString())->asReturnedValue(); } - return ctx->d()->engine->newString(e->baseUrl().resolved(url).toString())->asReturnedValue(); + return v4->newString(e->baseUrl().resolved(url).toString())->asReturnedValue(); } /*! @@ -983,7 +985,7 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx) QV8Engine *v8engine = ctx->d()->engine->v8Engine; QQmlEngine *engine = v8engine->engine(); - QQmlContextData *context = v8engine->callingContext(); + QQmlContextData *context = scope.engine->callingQmlContext(); Q_ASSERT(context); QQmlContext *effectiveContext = 0; if (context->isPragmaLibraryContext) @@ -1090,7 +1092,7 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx) QV8Engine *v8engine = ctx->d()->engine->v8Engine; QQmlEngine *engine = v8engine->engine(); - QQmlContextData *context = v8engine->callingContext(); + QQmlContextData *context = scope.engine->callingQmlContext(); Q_ASSERT(context); QQmlContextData *effectiveContext = context; if (context->isPragmaLibraryContext) @@ -1178,7 +1180,7 @@ ReturnedValue QtObject::method_locale(CallContext *ctx) return QQmlLocale::locale(ctx->engine(), code); } -Heap::QQmlBindingFunction::QQmlBindingFunction(QV4::FunctionObject *originalFunction) +Heap::QQmlBindingFunction::QQmlBindingFunction(const QV4::FunctionObject *originalFunction) : QV4::Heap::FunctionObject(originalFunction->scope(), originalFunction->name()) , originalFunction(originalFunction->d()) { @@ -1191,10 +1193,10 @@ void QQmlBindingFunction::initBindingLocation() d()->bindingLocation.line = frame.line; } -ReturnedValue QQmlBindingFunction::call(Managed *that, CallData *callData) +ReturnedValue QQmlBindingFunction::call(const Managed *that, CallData *callData) { - Scope scope(static_cast<QQmlBindingFunction*>(that)->engine()); - ScopedFunctionObject function(scope, static_cast<QQmlBindingFunction*>(that)->d()->originalFunction); + Scope scope(static_cast<const QQmlBindingFunction*>(that)->engine()); + ScopedFunctionObject function(scope, static_cast<const QQmlBindingFunction*>(that)->d()->originalFunction); return function->call(callData); } @@ -1256,7 +1258,7 @@ ReturnedValue QtObject::method_binding(CallContext *ctx) { if (ctx->argc() != 1) V4THROW_ERROR("binding() requires 1 argument"); - QV4::FunctionObject *f = ctx->args()[0].asFunctionObject(); + const QV4::FunctionObject *f = ctx->args()[0].as<FunctionObject>(); if (!f) V4THROW_TYPE("binding(): argument (binding expression) must be a function"); @@ -1267,7 +1269,7 @@ ReturnedValue QtObject::method_binding(CallContext *ctx) ReturnedValue QtObject::method_get_platform(CallContext *ctx) { // ### inefficient. Should be just a value based getter - Object *o = ctx->thisObject().asObject(); + Object *o = ctx->thisObject().as<Object>(); if (!o) return ctx->engine()->throwTypeError(); QtObject *qt = o->as<QtObject>(); @@ -1284,7 +1286,7 @@ ReturnedValue QtObject::method_get_platform(CallContext *ctx) ReturnedValue QtObject::method_get_application(CallContext *ctx) { // ### inefficient. Should be just a value based getter - Object *o = ctx->thisObject().asObject(); + Object *o = ctx->thisObject().as<Object>(); if (!o) return ctx->engine()->throwTypeError(); QtObject *qt = o->as<QtObject>(); @@ -1353,12 +1355,12 @@ static QString jsStack(QV4::ExecutionEngine *engine) { QString stackFrame; if (frame.column >= 0) - stackFrame = QString::fromLatin1("%1 (%2:%3:%4)").arg(frame.function, + stackFrame = QStringLiteral("%1 (%2:%3:%4)").arg(frame.function, frame.source, QString::number(frame.line), QString::number(frame.column)); else - stackFrame = QString::fromLatin1("%1 (%2:%3)").arg(frame.function, + stackFrame = QStringLiteral("%1 (%2:%3)").arg(frame.function, frame.source, QString::number(frame.line)); @@ -1379,7 +1381,7 @@ static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, CallContext *c if (i != 0) result.append(QLatin1Char(' ')); - if (ctx->args()[i].asArrayObject()) + if (ctx->args()[i].as<ArrayObject>()) result.append(QStringLiteral("[") + ctx->args()[i].toQStringNoThrow() + QStringLiteral("]")); else result.append(ctx->args()[i].toQStringNoThrow()); @@ -1446,10 +1448,11 @@ QV4::ReturnedValue ConsoleObject::method_profile(CallContext *ctx) const QByteArray baSource = frame.source.toUtf8(); const QByteArray baFunction = frame.function.toUtf8(); QMessageLogger logger(baSource.constData(), frame.line, baFunction.constData()); - if (!QQmlDebugService::isDebuggingEnabled()) { + QQmlProfilerService *service = QQmlDebugConnector::service<QQmlProfilerService>(); + if (!service) { logger.warning("Cannot start profiling because debug service is disabled. Start with -qmljsdebugger=port:XXXXX."); } else { - QQmlProfilerService::instance()->startProfiling(v4->qmlEngine()); + service->startProfiling(v4->qmlEngine()); logger.debug("Profiling started."); } @@ -1465,10 +1468,11 @@ QV4::ReturnedValue ConsoleObject::method_profileEnd(CallContext *ctx) const QByteArray baFunction = frame.function.toUtf8(); QMessageLogger logger(baSource.constData(), frame.line, baFunction.constData()); - if (!QQmlDebugService::isDebuggingEnabled()) { + QQmlProfilerService *service = QQmlDebugConnector::service<QQmlProfilerService>(); + if (!service) { logger.warning("Ignoring console.profileEnd(): the debug service is disabled."); } else { - QQmlProfilerService::instance()->stopProfiling(v4->qmlEngine()); + service->stopProfiling(v4->qmlEngine()); logger.debug("Profiling ended."); } @@ -1612,7 +1616,7 @@ void QV4::GlobalExtensions::init(QQmlEngine *qmlEngine, Object *globalObject) globalObject->defineDefaultProperty(QStringLiteral("Qt"), qt); // string prototype extension - v4->stringPrototype.asObject()->defineDefaultProperty(QStringLiteral("arg"), method_string_arg); + v4->stringPrototype()->defineDefaultProperty(QStringLiteral("arg"), method_string_arg); } @@ -1726,9 +1730,8 @@ ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx) V4THROW_ERROR("qsTr(): third argument (n) must be a number"); Scope scope(ctx); - QV8Engine *v8engine = ctx->d()->engine->v8Engine; QString context; - if (QQmlContextData *ctxt = v8engine->callingContext()) { + if (QQmlContextData *ctxt = scope.engine->callingQmlContext()) { QString path = ctxt->urlString(); int lastSlash = path.lastIndexOf(QLatin1Char('/')); int lastDot = path.lastIndexOf(QLatin1Char('.')); diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h index b78375118b..bdd53fe601 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h +++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h @@ -68,8 +68,8 @@ struct ConsoleObject : Object { }; struct QQmlBindingFunction : FunctionObject { - QQmlBindingFunction(QV4::FunctionObject *originalFunction); - FunctionObject *originalFunction; + QQmlBindingFunction(const QV4::FunctionObject *originalFunction); + Pointer<FunctionObject> originalFunction; // Set when the binding is created later QQmlSourceLocation bindingLocation; }; @@ -166,7 +166,7 @@ struct QQmlBindingFunction : public QV4::FunctionObject void initBindingLocation(); // from caller stack trace - static ReturnedValue call(Managed *that, CallData *callData); + static ReturnedValue call(const Managed *that, CallData *callData); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; diff --git a/src/qml/qml/v8/qv4domerrors.cpp b/src/qml/qml/v8/qv4domerrors.cpp index c318e2e550..1baaa113aa 100644 --- a/src/qml/qml/v8/qv4domerrors.cpp +++ b/src/qml/qml/v8/qv4domerrors.cpp @@ -59,7 +59,7 @@ void qt_add_domexceptions(ExecutionEngine *e) domexception->defineReadonlyProperty(QStringLiteral("INVALID_ACCESS_ERR"), Primitive::fromInt32(DOMEXCEPTION_INVALID_ACCESS_ERR)); domexception->defineReadonlyProperty(QStringLiteral("VALIDATION_ERR"), Primitive::fromInt32(DOMEXCEPTION_VALIDATION_ERR)); domexception->defineReadonlyProperty(QStringLiteral("TYPE_MISMATCH_ERR"), Primitive::fromInt32(DOMEXCEPTION_TYPE_MISMATCH_ERR)); - e->globalObject()->defineDefaultProperty(QStringLiteral("DOMException"), domexception); + e->globalObject->defineDefaultProperty(QStringLiteral("DOMException"), domexception); } QT_END_NAMESPACE diff --git a/src/qml/qml/v8/qv4sqlerrors.cpp b/src/qml/qml/v8/qv4sqlerrors.cpp index b7a5b71540..c61e57560d 100644 --- a/src/qml/qml/v8/qv4sqlerrors.cpp +++ b/src/qml/qml/v8/qv4sqlerrors.cpp @@ -51,7 +51,7 @@ void qt_add_sqlexceptions(QV4::ExecutionEngine *engine) sqlexception->defineReadonlyProperty(QStringLiteral("SYNTAX_ERR"), Primitive::fromInt32(SQLEXCEPTION_SYNTAX_ERR)); sqlexception->defineReadonlyProperty(QStringLiteral("CONSTRAINT_ERR"), Primitive::fromInt32(SQLEXCEPTION_CONSTRAINT_ERR)); sqlexception->defineReadonlyProperty(QStringLiteral("TIMEOUT_ERR"), Primitive::fromInt32(SQLEXCEPTION_TIMEOUT_ERR)); - engine->globalObject()->defineDefaultProperty(QStringLiteral("SQLException"), sqlexception); + engine->globalObject->defineDefaultProperty(QStringLiteral("SQLException"), sqlexception); } QT_END_NAMESPACE diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index a7c63c9df1..6cb316ce9f 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -61,7 +61,7 @@ #include <QtCore/qdatastream.h> #include <private/qsimd_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4dateobject_p.h> #include <private/qv4objectiterator_p.h> #include <private/qv4mm_p.h> @@ -171,15 +171,10 @@ const QSet<QString> &QV8Engine::illegalNames() const return m_illegalNames; } -QQmlContextData *QV8Engine::callingContext() -{ - return QV4::QmlContextWrapper::callingContext(m_v4Engine); -} - void QV8Engine::initializeGlobal() { QV4::Scope scope(m_v4Engine); - QV4::GlobalExtensions::init(m_engine, m_v4Engine->globalObject()); + QV4::GlobalExtensions::init(m_engine, m_v4Engine->globalObject); QQmlLocale::registerStringLocaleCompare(m_v4Engine); QQmlDateExtension::registerExtension(m_v4Engine); @@ -191,9 +186,9 @@ void QV8Engine::initializeGlobal() qt_add_sqlexceptions(m_v4Engine); { - for (uint i = 0; i < m_v4Engine->globalObject()->internalClass()->size; ++i) { - if (m_v4Engine->globalObject()->internalClass()->nameMap.at(i)) - m_illegalNames.insert(m_v4Engine->globalObject()->internalClass()->nameMap.at(i)->string); + for (uint i = 0; i < m_v4Engine->globalObject->internalClass()->size; ++i) { + if (m_v4Engine->globalObject->internalClass()->nameMap.at(i)) + m_illegalNames.insert(m_v4Engine->globalObject->internalClass()->nameMap.at(i)->string); } } @@ -229,7 +224,7 @@ void QV8Engine::freezeObject(const QV4::Value &value) QV4::ScopedFunctionObject f(scope, m_freezeObject.value()); QV4::ScopedCallData callData(scope, 1); callData->args[0] = value; - callData->thisObject = m_v4Engine->globalObject(); + callData->thisObject = m_v4Engine->globalObject; f->call(callData); } @@ -266,9 +261,7 @@ void QV8Engine::setExtensionData(int index, Deletable *data) void QV8Engine::initQmlGlobalObject() { initializeGlobal(); - QV4::Scope scope(m_v4Engine); - QV4::ScopedValue v(scope, m_v4Engine->globalObject()); - freezeObject(v); + freezeObject(*m_v4Engine->globalObject); } void QV8Engine::setEngine(QQmlEngine *engine) @@ -279,7 +272,7 @@ void QV8Engine::setEngine(QQmlEngine *engine) QV4::ReturnedValue QV8Engine::global() { - return m_v4Engine->globalObject()->asReturnedValue(); + return m_v4Engine->globalObject->asReturnedValue(); } void QV8Engine::startTimer(const QString &timerName) diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h index fb538772d1..5d12244dcb 100644 --- a/src/qml/qml/v8/qv8engine_p.h +++ b/src/qml/qml/v8/qv8engine_p.h @@ -60,7 +60,7 @@ #include <private/qqmlpropertycache_p.h> #include <private/qv4qobjectwrapper_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4object_p.h> #include <private/qv4identifier_p.h> @@ -101,19 +101,19 @@ namespace QV4 { return rv; \ } \ -// Used to allow a QObject method take and return raw V8 handles without having to expose -// v8 in the public API. +// Used to allow a QObject method take and return raw V4 handles without having to expose +// 48 in the public API. // Use like this: // class MyClass : public QObject { // Q_OBJECT // ... -// Q_INVOKABLE void myMethod(QQmlV8Function*); +// Q_INVOKABLE void myMethod(QQmlV4Function*); // }; // The QQmlV8Function - and consequently the arguments and return value - only remains // valid during the call. If the return value isn't set within myMethod(), the will return // undefined. class QV8Engine; -// ### GC + class QQmlV4Function { public: @@ -133,7 +133,7 @@ private: const QV4::Value &global, QQmlContextData *c, QV4::ExecutionEngine *e) : callData(callData), retVal(retVal), ctx(c), e(e) { - callData->thisObject.val = global.asReturnedValue(); + callData->thisObject = QV4::Value::fromReturnedValue(global.asReturnedValue()); } QV4::CallData *callData; @@ -163,8 +163,6 @@ class QQmlContextData; class Q_QML_PRIVATE_EXPORT QV8Engine { friend class QJSEngine; - // ### GC - typedef QSet<QV4::Heap::Object *> V8ObjectSet; public: static QV8Engine* get(QJSEngine* q) { Q_ASSERT(q); return q->handle(); } // static QJSEngine* get(QV8Engine* d) { Q_ASSERT(d); return d->q; } @@ -192,8 +190,6 @@ public: Deletable *listModelData() { return m_listModelData; } void setListModelData(Deletable *d) { if (m_listModelData) delete m_listModelData; m_listModelData = d; } - QQmlContextData *callingContext(); - void freezeObject(const QV4::Value &value); // Return the network access manager for this engine. By default this returns the network |