diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2020-01-09 01:00:43 +0100 |
---|---|---|
committer | Fabian Kosmale <fabian.kosmale@qt.io> | 2020-01-09 07:24:26 +0000 |
commit | ba10b0b9ed93be007fcb156710ef6081000e3ae3 (patch) | |
tree | ea17c625900b83d5955cb4a2db1587a5f07e2fb4 /src | |
parent | 653c25d48298fb747cf6f3b012816855c51d4260 (diff) | |
parent | 1798d20ded699837f7b3afe0bb340617af266518 (diff) |
Merge remote-tracking branch 'origin/5.14' into 5.15
Conflicts:
src/particles/qquickitemparticle.cpp
src/qmlmodels/qqmladaptormodel.cpp
tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp
Change-Id: Ibd8fbb91da6893a09f4ffe61ad0b95d8149bbc87
Diffstat (limited to 'src')
24 files changed, 247 insertions, 104 deletions
diff --git a/src/particles/qquickitemparticle.cpp b/src/particles/qquickitemparticle.cpp index 740d0f60f3..ce254c212d 100644 --- a/src/particles/qquickitemparticle.cpp +++ b/src/particles/qquickitemparticle.cpp @@ -136,6 +136,7 @@ QQuickItemParticle::QQuickItemParticle(QQuickItem *parent) : QQuickItemParticle::~QQuickItemParticle() { delete clock; + qDeleteAll(m_managed); } void QQuickItemParticle::freeze(QQuickItem* item) @@ -172,7 +173,8 @@ void QQuickItemParticle::give(QQuickItem *item) void QQuickItemParticle::initialize(int gIdx, int pIdx) { - m_loadables << m_system->groupData[gIdx]->data[pIdx];//defer to other thread + Q_UNUSED(gIdx); + Q_UNUSED(pIdx); } void QQuickItemParticle::commit(int, int) @@ -205,50 +207,43 @@ void QQuickItemParticle::tick(int time) { Q_UNUSED(time);//only needed because QTickAnimationProxy expects one processDeletables(); - - foreach (QQuickParticleData* d, m_loadables){ - Q_ASSERT(d); - if (m_stasis.contains(d->delegate)) - qWarning() << "Current model particles prefers overwrite:false"; - //remove old item from the particle that is dying to make room for this one - if (d->delegate) { - m_deletables << d->delegate; - d->delegate = nullptr; - } - QQuickItem* parentItem = nullptr; - if (!m_pendingItems.isEmpty()){ - QQuickItem *item = m_pendingItems.front(); - m_pendingItems.pop_front(); - parentItem = item->parentItem(); - d->delegate = item; - }else if (m_delegate){ - d->delegate = qobject_cast<QQuickItem*>(m_delegate->create(qmlContext(this))); - if (d->delegate) - m_managed << d->delegate; - } - if (d && d->delegate){//###Data can be zero if creating an item leads to a reset - this screws things up. - d->delegate->setX(d->curX(m_system) - d->delegate->width() / 2); //TODO: adjust for system? - d->delegate->setY(d->curY(m_system) - d->delegate->height() / 2); - QQuickItemParticleAttached* mpa = qobject_cast<QQuickItemParticleAttached*>(qmlAttachedPropertiesObject<QQuickItemParticle>(d->delegate)); - if (mpa){ - mpa->m_parentItem = parentItem; - mpa->m_mp = this; - mpa->attach(); + for (auto groupId : groupIds()) { + for (QQuickParticleData* d : qAsConst(m_system->groupData[groupId]->data)) { + if (!d->delegate && d->t != -1 && d->stillAlive(m_system)) { + QQuickItem* parentItem = nullptr; + if (!m_pendingItems.isEmpty()){ + QQuickItem *item = m_pendingItems.front(); + m_pendingItems.pop_front(); + parentItem = item->parentItem(); + d->delegate = item; + }else if (m_delegate){ + d->delegate = qobject_cast<QQuickItem*>(m_delegate->create(qmlContext(this))); + if (d->delegate) + m_managed << d->delegate; + } + if (d && d->delegate){//###Data can be zero if creating an item leads to a reset - this screws things up. + d->delegate->setX(d->curX(m_system) - d->delegate->width() / 2); //TODO: adjust for system? + d->delegate->setY(d->curY(m_system) - d->delegate->height() / 2); + QQuickItemParticleAttached* mpa = qobject_cast<QQuickItemParticleAttached*>(qmlAttachedPropertiesObject<QQuickItemParticle>(d->delegate)); + if (mpa){ + mpa->m_parentItem = parentItem; + mpa->m_mp = this; + mpa->attach(); + } + d->delegate->setParentItem(this); + if (m_fade) + d->delegate->setOpacity(0.); + d->delegate->setVisible(false);//Will be set to true when we prepare the next frame + m_activeCount++; + } } - d->delegate->setParentItem(this); - if (m_fade) - d->delegate->setOpacity(0.); - d->delegate->setVisible(false);//Will be set to true when we prepare the next frame - m_activeCount++; } } - m_loadables.clear(); } void QQuickItemParticle::reset() { QQuickParticlePainter::reset(); - m_loadables.clear(); // delete all managed items which had their logical particles cleared // but leave it alone if the logical particle is maintained @@ -258,7 +253,7 @@ void QQuickItemParticle::reset() lost.remove(d->delegate); } } - m_deletables.append(lost.values()); + m_deletables.unite(lost); //TODO: This doesn't yet handle calling detach on taken particles in the system reset case processDeletables(); } @@ -267,18 +262,9 @@ void QQuickItemParticle::reset() QSGNode* QQuickItemParticle::updatePaintNode(QSGNode* n, UpdatePaintNodeData* d) { //Dummy update just to get painting tick - if (m_pleaseReset){ + if (m_pleaseReset) m_pleaseReset = false; - //Refill loadables, delayed here so as to only happen once per frame max - //### Constant resetting might lead to m_loadables never being populated when tick() occurs - for (auto groupId : groupIds()) { - for (QQuickParticleData* d : qAsConst(m_system->groupData[groupId]->data)) { - if (!d->delegate && d->t != -1 && d->stillAlive(m_system)) { - m_loadables << d; - } - } - } - } + prepareNextFrame(); update();//Get called again diff --git a/src/particles/qquickitemparticle_p.h b/src/particles/qquickitemparticle_p.h index ea46c67db7..32c9881691 100644 --- a/src/particles/qquickitemparticle_p.h +++ b/src/particles/qquickitemparticle_p.h @@ -108,9 +108,8 @@ protected: private: void processDeletables(); void tick(int time = 0); - QList<QQuickItem* > m_deletables; + QSet<QQuickItem* > m_deletables; QList<QQuickItem* > m_managed; - QList< QQuickParticleData* > m_loadables; bool m_fade; QList<QQuickItem*> m_pendingItems; diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index 654d33b8d1..1c587d2367 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -586,7 +586,7 @@ uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n) obj->arrayPut(oldSize, os->values.data() + os->offset, chunk); toCopy -= chunk; if (toCopy) - obj->arrayPut(oldSize + chunk, os->values.data(), toCopy); + obj->setArrayLength(oldSize + chunk + toCopy); } return oldSize + n; @@ -659,6 +659,12 @@ bool ArrayElementLessThan::operator()(Value v1, Value v2) const } ScopedString p1s(scope, v1.toString(scope.engine)); ScopedString p2s(scope, v2.toString(scope.engine)); + + if (!p1s) + return false; + if (!p2s) + return true; + return p1s->toQString() < p2s->toQString(); } diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index d8d0d4739f..6c51b4cbcb 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -1048,8 +1048,9 @@ ReturnedValue ArrayPrototype::method_includes(const FunctionObject *b, const Val } } + ScopedValue val(scope); while (k < len) { - ScopedValue val(scope, instance->get(k)); + val = instance->get(k); if (val->sameValueZero(argv[0])) { return Encode(true); } diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index cd2327a45e..14eaa5bce8 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -43,6 +43,7 @@ #include <private/qqmljsdiagnosticmessage_p.h> #include <QtCore/QTextStream> +#include <QtCore/private/qvariant_p.h> #include <QDateTime> #include <QDir> #include <QFileInfo> @@ -118,6 +119,7 @@ #endif #include <private/qv4sqlerrors_p.h> #include <qqmlfile.h> +#include <qmetatype.h> #if USE(PTHREADS) # include <pthread.h> @@ -185,6 +187,91 @@ static void restoreJSValue(QDataStream &stream, void *data) } } +struct JSArrayIterator { + QJSValue const* data; + quint32 index; +}; + +namespace { +void createNewIteratorIfNonExisting(void **iterator) { + if (*iterator == nullptr) + *iterator = new JSArrayIterator; +} +} + +static QtMetaTypePrivate::QSequentialIterableImpl jsvalueToSequence (const QJSValue& value) { + using namespace QtMetaTypePrivate; + + QSequentialIterableImpl iterator {}; + if (!value.isArray()) { + // set up some functions so that non-array QSequentialIterables do not crash + // but instead appear as an empty sequence + iterator._size = [](const void *) {return 0;}; + iterator._moveToBegin = [](const void *, void **) {}; + iterator._moveToEnd = [](const void *, void **) {}; + iterator._advance = [](void **, int) {}; + iterator._equalIter = [](void * const *, void * const *){return true; /*all iterators are nullptr*/}; + iterator._destroyIter = [](void **){}; + return iterator; + } + + iterator._iterable = &value; + iterator._iterator = nullptr; + iterator._metaType_id = qMetaTypeId<QVariant>(); + iterator._metaType_flags = QVariantConstructionFlags::ShouldDeleteVariantData; + iterator._iteratorCapabilities = RandomAccessCapability | BiDirectionalCapability | ForwardCapability; + iterator._size = [](const void *p) -> int { + return static_cast<QJSValue const *>(p)->property(QString::fromLatin1("length")).toInt(); + }; + /* Lifetime management notes: + * _at and _get return a pointer to a JSValue allocated via QMetaType::create + * Because we set QVariantConstructionFlags::ShouldDeleteVariantData, QSequentialIterable::at + * and QSequentialIterable::operator*() will free that memory + */ + + iterator._at = [](const void *iterable, int index) -> void const * { + auto const value = static_cast<QJSValue const *>(iterable)->property(quint32(index)).toVariant(); + return QMetaType::create(qMetaTypeId<QVariant>(), &value); + }; + iterator._moveToBegin = [](const void *iterable, void **iterator) { + createNewIteratorIfNonExisting(iterator); + auto jsArrayIterator = static_cast<JSArrayIterator *>(*iterator); + jsArrayIterator->index = 0; + jsArrayIterator->data = reinterpret_cast<QJSValue const*>(iterable); + }; + iterator._moveToEnd = [](const void *iterable, void **iterator) { + createNewIteratorIfNonExisting(iterator); + auto jsArrayIterator = static_cast<JSArrayIterator *>(*iterator); + auto length = static_cast<QJSValue const *>(iterable)->property(QString::fromLatin1("length")).toInt(); + jsArrayIterator->data = reinterpret_cast<QJSValue const*>(iterable); + jsArrayIterator->index = quint32(length); + }; + iterator._advance = [](void **iterator, int advanceBy) { + static_cast<JSArrayIterator *>(*iterator)->index += quint32(advanceBy); + }; + iterator._get = []( void * const *iterator, int metaTypeId, uint flags) -> VariantData { + auto const * const arrayIterator = static_cast<const JSArrayIterator *>(*iterator); + QJSValue const * const jsArray = arrayIterator->data; + auto const value = jsArray->property(arrayIterator->index).toVariant(); + Q_ASSERT(flags & QVariantConstructionFlags::ShouldDeleteVariantData); + return {metaTypeId, QMetaType::create(qMetaTypeId<QVariant>(), &value), flags}; + }; + iterator._destroyIter = [](void **iterator) { + delete static_cast<JSArrayIterator *>(*iterator); + }; + iterator._equalIter = [](void * const *p, void * const *other) { + auto this_ = static_cast<const JSArrayIterator *>(*p); + auto that_ = static_cast<const JSArrayIterator *>(*other); + return this_->index == that_->index && this_->data == that_->data; + }; + iterator._copyIter = [](void **iterator, void * const * otherIterator) { + auto *otherIter = (static_cast<JSArrayIterator const *>(*otherIterator)); + static_cast<JSArrayIterator *>(*iterator)->index = otherIter->index; + static_cast<JSArrayIterator *>(*iterator)->data = otherIter->data; + }; + return iterator; +} + ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) : executableAllocator(new QV4::ExecutableAllocator) , regExpAllocator(new QV4::ExecutableAllocator) @@ -712,6 +799,8 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) QMetaType::registerConverter<QJSValue, QVariantList>(convertJSValueToVariantType<QVariantList>); if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QStringList>()) QMetaType::registerConverter<QJSValue, QStringList>(convertJSValueToVariantType<QStringList>); + if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QtMetaTypePrivate::QSequentialIterableImpl>()) + QMetaType::registerConverter<QJSValue, QtMetaTypePrivate::QSequentialIterableImpl>(jsvalueToSequence); QMetaType::registerStreamOperators(qMetaTypeId<QJSValue>(), saveJSValue, restoreJSValue); QV4::QObjectWrapper::initializeBindings(this); @@ -1178,8 +1267,11 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file) void ExecutionEngine::markObjects(MarkStack *markStack) { for (int i = 0; i < NClasses; ++i) - if (classes[i]) + if (classes[i]) { classes[i]->mark(markStack); + if (markStack->top >= markStack->limit) + markStack->drain(); + } markStack->drain(); identifierTable->markObjects(markStack); @@ -2238,4 +2330,9 @@ int ExecutionEngine::registerExtension() return registrationData()->extensionCount++; } +QNetworkAccessManager *QV4::detail::getNetworkAccessManager(ExecutionEngine *engine) +{ + return engine->qmlEngine()->networkAccessManager(); +} + QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index d233347060..e0025feb00 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -91,7 +91,14 @@ class PageAllocation; QT_BEGIN_NAMESPACE -namespace QV4 { struct QObjectMethod; } +class QNetworkAccessManager; + +namespace QV4 { +struct QObjectMethod; +namespace detail { +QNetworkAccessManager *getNetworkAccessManager(ExecutionEngine *engine); +} +} // Used to allow a QObject method take and return raw V4 handles without having to expose // 48 in the public API. @@ -348,6 +355,8 @@ public: FunctionObject *getStackFunction() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetStack_Function); } FunctionObject *thrower() const { return reinterpret_cast<FunctionObject *>(jsObjects + ThrowerObject); } + QNetworkAccessManager* (*networkAccessManager)(ExecutionEngine*) = detail::getNetworkAccessManager; + enum JSStrings { String_Empty, String_undefined, diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 6fb7946023..dfef52583e 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -364,7 +364,13 @@ ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, cons if (!arr) return v4->throwTypeError(); - uint len = arr->getLength(); + const qint64 len64 = arr->getLength(); + if (len64 < 0ll || len64 > qint64(std::numeric_limits<int>::max())) + return v4->throwRangeError(QStringLiteral("Invalid array length.")); + if (len64 > qint64(v4->jsStackLimit - v4->jsStackTop)) + return v4->throwRangeError(QStringLiteral("Array too large for apply().")); + + const uint len = uint(len64); Scope scope(v4); Value *arguments = scope.alloc<Scope::Uninitialized>(len); diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index f3375929a3..9e901d6a34 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -157,7 +157,7 @@ struct Q_QML_EXPORT Object: Managed { const Value *propertyData(uint index) const { return d()->propertyData(index); } Heap::ArrayData *arrayData() const { return d()->arrayData; } - void setArrayData(ArrayData *a) { d()->arrayData.set(engine(), a->d()); } + void setArrayData(ArrayData *a) { d()->arrayData.set(engine(), a ? a->d() : nullptr); } void getProperty(const InternalClassEntry &entry, Property *p) const; void setProperty(const InternalClassEntry &entry, const Property *p); diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp index e529b8e86b..65f6fa8b12 100644 --- a/src/qml/jsruntime/qv4objectiterator.cpp +++ b/src/qml/jsruntime/qv4objectiterator.cpp @@ -182,7 +182,7 @@ PropertyKey ForInIteratorObject::nextProperty() const if (d()->current != d()->object) { o = d()->object; bool shadowed = false; - while (o->d() != c->heapObject()) { + while (o && o->d() != c->heapObject()) { if (o->getOwnProperty(key) != Attr_Invalid) { shadowed = true; break; diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 3d3b3f413f..7d910a1cbc 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -658,6 +658,7 @@ ReturnedValue ObjectPrototype::method_toString(const FunctionObject *b, const Va ReturnedValue ObjectPrototype::method_toLocaleString(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { Scope scope(b); + CHECK_STACK_LIMITS(scope.engine) ScopedObject o(scope, thisObject->toObject(scope.engine)); if (!o) RETURN_UNDEFINED(); diff --git a/src/qml/jsruntime/qv4proxy.cpp b/src/qml/jsruntime/qv4proxy.cpp index 9325e2e53b..51f96b9003 100644 --- a/src/qml/jsruntime/qv4proxy.cpp +++ b/src/qml/jsruntime/qv4proxy.cpp @@ -515,7 +515,7 @@ ProxyObjectOwnPropertyKeyIterator::ProxyObjectOwnPropertyKeyIterator(ArrayObject PropertyKey ProxyObjectOwnPropertyKeyIterator::next(const Object *m, Property *pd, PropertyAttributes *attrs) { - if (index >= len) + if (index >= len || m == nullptr) return PropertyKey::invalid(); Scope scope(m); diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp index 4ed1dbd5aa..76daead842 100644 --- a/src/qml/jsruntime/qv4regexp.cpp +++ b/src/qml/jsruntime/qv4regexp.cpp @@ -73,14 +73,13 @@ DEFINE_MANAGED_VTABLE(RegExp); uint RegExp::match(const QString &string, int start, uint *matchOffsets) { - static const uint offsetJITFail = std::numeric_limits<unsigned>::max() - 1; - if (!isValid()) return JSC::Yarr::offsetNoMatch; WTF::String s(string); #if ENABLE(YARR_JIT) + static const uint offsetJITFail = std::numeric_limits<unsigned>::max() - 1; auto *priv = d(); if (priv->hasValidJITCode()) { uint ret = JSC::Yarr::offsetNoMatch; diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index c1a42c4afa..f1375e4ca4 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -961,8 +961,8 @@ ReturnedValue RegExpPrototype::method_compile(const FunctionObject *b, const Val return scope.engine->throwTypeError(); Scoped<RegExpObject> re(scope, scope.engine->regExpCtor()->callAsConstructor(argv, argc)); - - r->d()->value.set(scope.engine, re->value()); + if (re) // Otherwise the regexp constructor should have thrown an exception + r->d()->value.set(scope.engine, re->value()); return Encode::undefined(); } diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index 9c50ac2b95..2ed1971235 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -1409,7 +1409,8 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_set(const FunctionObject *b, if (scope.engine->hasException || l != len) return scope.engine->throwTypeError(); - if (offset + l > a->length()) + const uint aLength = a->length(); + if (offset > aLength || l > aLength - offset) RETURN_RESULT(scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range"))); uint idx = 0; @@ -1439,7 +1440,9 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_set(const FunctionObject *b, return scope.engine->throwTypeError(); uint l = srcTypedArray->length(); - if (offset + l > a->length()) + + const uint aLength = a->length(); + if (offset > aLength || l > aLength - offset) RETURN_RESULT(scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range"))); char *dest = buffer->d()->data->data() + a->d()->byteOffset + offset*elementSize; diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 4e901721cb..ae12033eb4 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -555,6 +555,8 @@ struct ValueArray { } else { while (v < end) { v->mark(markStack); + if (markStack->top >= markStack->limit) + markStack->drain(); ++v; } } diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 3465036c86..35b2ff2749 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -1220,6 +1220,8 @@ void MemoryManager::collectFromJSStack(MarkStack *markStack) const Q_ASSERT(m->inUse()); // Skip pointers to already freed objects, they are bogus as well m->mark(markStack); + if (markStack->top >= markStack->limit) + markStack->drain(); } ++v; } diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp index adb036e2d0..7f80fe5e1c 100644 --- a/src/qml/qml/qqmlapplicationengine.cpp +++ b/src/qml/qml/qqmlapplicationengine.cpp @@ -127,7 +127,7 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c) switch (c->status()) { case QQmlComponent::Error: qWarning() << "QQmlApplicationEngine failed to load component"; - qWarning() << qPrintable(c->errorString()); + warning(c->errors()); q->objectCreated(nullptr, c->url()); break; case QQmlComponent::Ready: { diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index df4639bb1d..c2e7be73e7 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -1651,7 +1651,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject Scope scope(f->engine()); const QQmlXMLHttpRequestCtor *ctor = static_cast<const QQmlXMLHttpRequestCtor *>(f); - QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->qmlEngine()->networkAccessManager(), scope.engine); + QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->networkAccessManager(scope.engine), scope.engine); Scoped<QQmlXMLHttpRequestWrapper> w(scope, scope.engine->memoryManager->allocate<QQmlXMLHttpRequestWrapper>(r)); ScopedObject proto(scope, ctor->d()->proto); w->setPrototypeUnchecked(proto); diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index d634a48443..f5e723419e 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -1553,11 +1553,12 @@ static QString jsStack(QV4::ExecutionEngine *engine) { return stack; } -static QString serializeArray(Object *array, ExecutionEngine *v4) { +static QString serializeArray(Object *array, ExecutionEngine *v4, QSet<QV4::Heap::Object *> &alreadySeen) { Scope scope(v4); ScopedValue val(scope); QString result; + alreadySeen.insert(array->d()); result += QLatin1Char('['); const uint length = array->getLength(); for (uint i = 0; i < length; ++i) { @@ -1565,12 +1566,15 @@ static QString serializeArray(Object *array, ExecutionEngine *v4) { result += QLatin1Char(','); val = array->get(i); if (val->isManaged() && val->managed()->isArrayLike()) - result += serializeArray(val->objectValue(), v4); + if (!alreadySeen.contains(val->objectValue()->d())) + result += serializeArray(val->objectValue(), v4, alreadySeen); + else + result += QLatin1String("[Circular]"); else result += val->toQStringNoThrow(); } result += QLatin1Char(']'); - + alreadySeen.remove(array->d()); return result; }; @@ -1600,8 +1604,9 @@ static ReturnedValue writeToConsole(const FunctionObject *b, const Value *, cons if (i != start) result.append(QLatin1Char(' ')); + QSet<QV4::Heap::Object *> alreadySeenElements; if (argv[i].isManaged() && argv[i].managed()->isArrayLike()) - result.append(serializeArray(argv[i].objectValue(), v4)); + result.append(serializeArray(argv[i].objectValue(), v4, alreadySeenElements)); else result.append(argv[i].toQStringNoThrow()); } diff --git a/src/qmlmodels/qqmladaptormodel.cpp b/src/qmlmodels/qqmladaptormodel.cpp index 012540244f..cf0d8fbb2f 100644 --- a/src/qmlmodels/qqmladaptormodel.cpp +++ b/src/qmlmodels/qqmladaptormodel.cpp @@ -199,12 +199,11 @@ public: RETURN_RESULT(scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"))); const QQmlAdaptorModel *const model = static_cast<QQmlDMCachedModelData *>(o->d()->item)->type->model; - if (o->d()->item->index >= 0 && *model) { - const QAbstractItemModel * const aim = model->aim(); - RETURN_RESULT(QV4::Encode(aim->hasChildren(aim->index(o->d()->item->index, 0, model->rootIndex)))); - } else { - RETURN_RESULT(QV4::Encode(false)); + if (o->d()->item->index >= 0) { + if (const QAbstractItemModel *const aim = model->aim()) + RETURN_RESULT(QV4::Encode(aim->hasChildren(aim->index(o->d()->item->index, 0, model->rootIndex)))); } + RETURN_RESULT(QV4::Encode(false)); } @@ -400,23 +399,24 @@ public: bool hasModelChildren() const { - if (index >= 0 && *type->model) { - const QAbstractItemModel * const model = type->model->aim(); - return model->hasChildren(model->index(row, column, type->model->rootIndex)); - } else { - return false; + if (index >= 0) { + if (const QAbstractItemModel *const model = type->model->aim()) + return model->hasChildren(model->index(row, column, type->model->rootIndex)); } + return false; } QVariant value(int role) const override { - return type->model->aim()->index(row, column, type->model->rootIndex).data(role); + if (const QAbstractItemModel *aim = type->model->aim()) + return aim->index(row, column, type->model->rootIndex).data(role); + return QVariant(); } void setValue(int role, const QVariant &value) override { - type->model->aim()->setData( - type->model->aim()->index(row, column, type->model->rootIndex), value, role); + if (QAbstractItemModel *aim = type->model->aim()) + aim->setData(aim->index(row, column, type->model->rootIndex), value, role); } QV4::ReturnedValue get() override @@ -444,12 +444,16 @@ public: int rowCount(const QQmlAdaptorModel &model) const override { - return model.aim()->rowCount(model.rootIndex); + if (const QAbstractItemModel *aim = model.aim()) + return aim->rowCount(model.rootIndex); + return 0; } int columnCount(const QQmlAdaptorModel &model) const override { - return model.aim()->columnCount(model.rootIndex); + if (const QAbstractItemModel *aim = model.aim()) + return aim->columnCount(model.rootIndex); + return 0; } void cleanup(QQmlAdaptorModel &) const override @@ -464,39 +468,46 @@ public: dataType->initializeMetaType(model); } - QHash<QByteArray, int>::const_iterator it = roleNames.find(role.toUtf8()); - if (it != roleNames.end()) { - return model.aim()->index(model.rowAt(index), model.columnAt(index), model.rootIndex).data(*it); - } else if (role == QLatin1String("hasModelChildren")) { - return QVariant(model.aim()->hasChildren(model.aim()->index(model.rowAt(index), model.columnAt(index), model.rootIndex))); - } else { - return QVariant(); + if (const QAbstractItemModel *aim = model.aim()) { + QHash<QByteArray, int>::const_iterator it = roleNames.find(role.toUtf8()); + if (it != roleNames.end()) { + return aim->index(model.rowAt(index), model.columnAt(index), + model.rootIndex).data(*it); + } else if (role == QLatin1String("hasModelChildren")) { + return QVariant(aim->hasChildren(aim->index(model.rowAt(index), + model.columnAt(index), + model.rootIndex))); + } } + return QVariant(); } QVariant parentModelIndex(const QQmlAdaptorModel &model) const override { - return model - ? QVariant::fromValue(model.aim()->parent(model.rootIndex)) - : QVariant(); + if (const QAbstractItemModel *aim = model.aim()) + return QVariant::fromValue(aim->parent(model.rootIndex)); + return QVariant(); } QVariant modelIndex(const QQmlAdaptorModel &model, int index) const override { - return model - ? QVariant::fromValue(model.aim()->index(model.rowAt(index), model.columnAt(index), model.rootIndex)) - : QVariant(); + if (const QAbstractItemModel *aim = model.aim()) + return QVariant::fromValue(aim->index(model.rowAt(index), model.columnAt(index), + model.rootIndex)); + return QVariant(); } bool canFetchMore(const QQmlAdaptorModel &model) const override { - return model && model.aim()->canFetchMore(model.rootIndex); + if (const QAbstractItemModel *aim = model.aim()) + return aim->canFetchMore(model.rootIndex); + return false; } void fetchMore(QQmlAdaptorModel &model) const override { - if (model) - model.aim()->fetchMore(model.rootIndex); + if (QAbstractItemModel *aim = model.aim()) + aim->fetchMore(model.rootIndex); } QQmlDelegateModelItem *createItem( @@ -516,7 +527,8 @@ public: setModelDataType<QQmlDMAbstractItemModelData>(&builder, this); const QByteArray propertyType = QByteArrayLiteral("QVariant"); - const QHash<int, QByteArray> names = model.aim()->roleNames(); + const QAbstractItemModel *aim = model.aim(); + const QHash<int, QByteArray> names = aim ? aim->roleNames() : QHash<int, QByteArray>(); for (QHash<int, QByteArray>::const_iterator it = names.begin(), cend = names.end(); it != cend; ++it) { const int propertyId = propertyRoles.count(); propertyRoles.append(it.key()); diff --git a/src/qmlworkerscript/qquickworkerscript.cpp b/src/qmlworkerscript/qquickworkerscript.cpp index 9e4b3e1b46..72ae6d5bd4 100644 --- a/src/qmlworkerscript/qquickworkerscript.cpp +++ b/src/qmlworkerscript/qquickworkerscript.cpp @@ -130,6 +130,7 @@ struct WorkerScript : public QV4::ExecutionEngine { QQuickWorkerScriptEnginePrivate *p = nullptr; QUrl source; QQuickWorkerScript *owner = nullptr; + QScopedPointer<QNetworkAccessManager> scriptLocalNAM; int id = -1; }; @@ -389,6 +390,16 @@ WorkerScript::WorkerScript(int id, QQuickWorkerScriptEnginePrivate *parent) QV4::ScopedValue sendMessage(scope, QV4::FunctionObject::createBuiltinFunction(this, name, QQuickWorkerScriptEnginePrivate::method_sendMessage, 1)); api->put(QV4::ScopedString(scope, scope.engine->newString(QStringLiteral("sendMessage"))), sendMessage); globalObject->put(QV4::ScopedString(scope, scope.engine->newString(QStringLiteral("WorkerScript"))), api); + networkAccessManager = [](QV4::ExecutionEngine *engine){ + auto *workerScript = static_cast<WorkerScript *>(engine); + if (workerScript->scriptLocalNAM) + return workerScript->scriptLocalNAM.get(); + if (auto *namFactory = workerScript->p->qmlengine->networkAccessManagerFactory()) + workerScript->scriptLocalNAM.reset(namFactory->create(workerScript->p)); + else + workerScript->scriptLocalNAM.reset(new QNetworkAccessManager(workerScript->p)); + return workerScript->scriptLocalNAM.get(); + }; } int QQuickWorkerScriptEngine::registerWorkerScript(QQuickWorkerScript *owner) diff --git a/src/quick/configure.json b/src/quick/configure.json index 0cb1e7470b..f8277332dc 100644 --- a/src/quick/configure.json +++ b/src/quick/configure.json @@ -3,9 +3,11 @@ "depends": [ "core-private", "qml-private", + "gui", "gui-private", "qmlmodels-private" ], + "condition": "module.gui", "testDir": "../../config.tests", "commandline": { diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index bc0d04c763..baef37a0ff 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -533,7 +533,7 @@ public: void refWindow(QQuickWindow *); void derefWindow(); - QQuickItem *subFocusItem; + QPointer<QQuickItem> subFocusItem; void updateSubFocusItem(QQuickItem *scope, bool focus); QTransform windowToItemTransform() const; diff --git a/src/quick/scenegraph/qsgrhitextureglyphcache.cpp b/src/quick/scenegraph/qsgrhitextureglyphcache.cpp index d0108bc56e..89c9ea4d5b 100644 --- a/src/quick/scenegraph/qsgrhitextureglyphcache.cpp +++ b/src/quick/scenegraph/qsgrhitextureglyphcache.cpp @@ -145,7 +145,9 @@ void QSGRhiTextureGlyphCache::prepareGlyphImage(QImage *img) { const int maskWidth = img->width(); const int maskHeight = img->height(); +#if Q_BYTE_ORDER != Q_BIG_ENDIAN const bool supportsBgra = m_rhi->isTextureFormatSupported(QRhiTexture::BGRA8); +#endif m_bgra = false; if (img->format() == QImage::Format_Mono) { |