diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2018-11-24 01:00:07 +0100 |
---|---|---|
committer | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2018-11-24 01:00:07 +0100 |
commit | df8784fa1fc4792007393ea995756c2d490691d7 (patch) | |
tree | d4b8d6bdc855e4045c39f7710f206b7cfcf3d493 | |
parent | b799e061a3cbf995ac7c88b315f5916e3a687162 (diff) | |
parent | 5246b910771e0dd824b4eea7c5245e5f9f3a63f0 (diff) |
Merge remote-tracking branch 'origin/5.12' into dev
Change-Id: I57e4b762dcccf2f7f6e4b659f6fc8c40465d3322
49 files changed, 449 insertions, 87 deletions
diff --git a/src/particles/particles.pro b/src/particles/particles.pro index ab1c854253..6a3fb1bdc4 100644 --- a/src/particles/particles.pro +++ b/src/particles/particles.pro @@ -6,7 +6,7 @@ CONFIG += internal_module QT = core-private gui-private qml-private quick-private DEFINES += QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES -win32-msvc*:DEFINES *= _CRT_SECURE_NO_WARNINGS +msvc:DEFINES *= _CRT_SECURE_NO_WARNINGS solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2 exists("qqml_enable_gcov") { diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc index eba1efd51f..171b2b6a11 100644 --- a/src/qml/doc/src/cppintegration/data.qdoc +++ b/src/qml/doc/src/cppintegration/data.qdoc @@ -91,7 +91,7 @@ when passed from C++ to QML and vice-versa: \li QFont \li \l font \row - \li QDate + \li QDateTime \li \l date \row \li QPoint, QPointF diff --git a/src/qml/doc/src/qmltypereference.qdoc b/src/qml/doc/src/qmltypereference.qdoc index 79bfdc7042..ae36ebbcc9 100644 --- a/src/qml/doc/src/qmltypereference.qdoc +++ b/src/qml/doc/src/qmltypereference.qdoc @@ -91,10 +91,17 @@ provided: The \c date type refers to a date value, including the time of the day. -To create a \c date value, specify it as a "YYYY-MM-DD" string: +To create a \c date value, specify it as a "YYYY-MM-DDThh:mm:ss.zzzZ" string. +(The T is literal, YYYY is a full year number, MM and DD are month and day +numbers, hh, mm and ss are hours, minutes and seconds, with .zzz as +milliseconds and Z as time-zone offset. The T and following time are optional. +If they are omitted, the date is handled as the start of UTC's day, which +falls on other dates in some time-zones. When T is included, the :ss.zzz or +just .zzz part can be omitted. With or without those, the zone offset can be +omitted, in which case local time is used.) For example: \qml -MyDatePicker { minDate: "2000-01-01"; maxDate: "2020-12-31" } +MyDatePicker { minDate: "2000-01-01 0:0"; maxDate: "2020-12-31 23:59" } \endqml To read a date value returned from a C++ extension class, use @@ -102,7 +109,13 @@ To read a date value returned from a C++ extension class, use When integrating with C++, note that any QDate or QDateTime value \l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically -converted into a \c date value, and vice-versa. +converted into a \c date value, and vice-versa. Note, however, that +converting a QDate will result in UTC's start of the day, which falls on +a different date in some other time-zones. It is usually more robust +to convert the QDate via a QDateTime explicitly, specifying local-time +or a relevant time-zone and selecting a time of day (such as noon) +that reliably exists (daylight-savings transitions skip an hour, near +one end or the other of a day). This basic type is provided by the QML language. It can be implicitly converted to a \l{QtQml::Date}{Date} object. diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp index b3ae630a95..225a4443d9 100644 --- a/src/qml/jsapi/qjsvalue.cpp +++ b/src/qml/jsapi/qjsvalue.cpp @@ -80,7 +80,7 @@ used to test if a value is of a certain type. The methods named toT() (e.g. toBool(), toString()) can be used to convert a QJSValue to another type. You can also use the generic - QJSValue_cast() function. + qjsvalue_cast() function. Object values have zero or more properties which are themselves QJSValues. Use setProperty() to set a property of an object, and diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 2e7c994550..8637db3dfd 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -60,11 +60,13 @@ void Heap::ArrayCtor::init(QV4::ExecutionContext *scope) Heap::FunctionObject::init(scope, QStringLiteral("Array")); } -ReturnedValue ArrayCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *) +ReturnedValue ArrayCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) { ExecutionEngine *v4 = static_cast<const ArrayCtor *>(f)->engine(); Scope scope(v4); ScopedArrayObject a(scope, v4->newArrayObject()); + if (newTarget) + a->setProtoFromNewTarget(newTarget); uint len; if (argc == 1 && argv[0].isNumber()) { bool ok; diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h index 04ec7e1607..c959b71bc6 100644 --- a/src/qml/jsruntime/qv4arrayobject_p.h +++ b/src/qml/jsruntime/qv4arrayobject_p.h @@ -70,7 +70,7 @@ struct ArrayCtor: FunctionObject { V4_OBJECT2(ArrayCtor, FunctionObject) - static ReturnedValue virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *); + static ReturnedValue virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget); static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); }; diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp index 075ee1657e..3e5f51c302 100644 --- a/src/qml/jsruntime/qv4booleanobject.cpp +++ b/src/qml/jsruntime/qv4booleanobject.cpp @@ -50,10 +50,18 @@ void Heap::BooleanCtor::init(QV4::ExecutionContext *scope) Heap::FunctionObject::init(scope, QStringLiteral("Boolean")); } -ReturnedValue BooleanCtor::virtualCallAsConstructor(const FunctionObject *that, const Value *argv, int argc, const Value *) +ReturnedValue BooleanCtor::virtualCallAsConstructor(const FunctionObject *that, const Value *argv, int argc, const Value *newTarget) { + auto v4 = that->engine(); bool n = argc ? argv[0].toBoolean() : false; - return Encode(that->engine()->newBooleanObject(n)); + + ReturnedValue o = Encode(v4->newBooleanObject(n)); + if (!newTarget) + return o; + Scope scope(v4); + ScopedObject obj(scope, o); + obj->setProtoFromNewTarget(newTarget); + return obj->asReturnedValue(); } ReturnedValue BooleanCtor::virtualCall(const FunctionObject *, const Value *, const Value *argv, int argc) diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index d8d428237b..21c6a5d06b 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -755,16 +755,16 @@ void Heap::DateCtor::init(QV4::ExecutionContext *scope) Heap::FunctionObject::init(scope, QStringLiteral("Date")); } -ReturnedValue DateCtor::virtualCallAsConstructor(const FunctionObject *that, const Value *argv, int argc, const Value *) +ReturnedValue DateCtor::virtualCallAsConstructor(const FunctionObject *that, const Value *argv, int argc, const Value *newTarget) { - ExecutionEngine *e = that->engine(); + ExecutionEngine *v4 = that->engine(); double t = 0; if (argc == 0) t = currentTime(); else if (argc == 1) { - Scope scope(e); + Scope scope(v4); ScopedValue arg(scope, argv[0]); if (DateObject *d = arg->as<DateObject>()) { t = d->date(); @@ -772,7 +772,7 @@ ReturnedValue DateCtor::virtualCallAsConstructor(const FunctionObject *that, con arg = RuntimeHelpers::toPrimitive(arg, PREFERREDTYPE_HINT); if (String *s = arg->stringValue()) - t = ParseString(s->toQString(), e->localTZA); + t = ParseString(s->toQString(), v4->localTZA); else t = TimeClip(arg->toNumber()); } @@ -789,10 +789,16 @@ ReturnedValue DateCtor::virtualCallAsConstructor(const FunctionObject *that, con if (year >= 0 && year <= 99) year += 1900; t = MakeDate(MakeDay(year, month, day), MakeTime(hours, mins, secs, ms)); - t = TimeClip(UTC(t, e->localTZA)); + t = TimeClip(UTC(t, v4->localTZA)); } - return Encode(e->newDateObject(Value::fromDouble(t))); + ReturnedValue o = Encode(v4->newDateObject(Value::fromDouble(t))); + if (!newTarget) + return o; + Scope scope(v4); + ScopedObject obj(scope, o); + obj->setProtoFromNewTarget(newTarget); + return obj->asReturnedValue(); } ReturnedValue DateCtor::virtualCall(const FunctionObject *m, const Value *, const Value *, int) diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 93cc55f8ad..dfe9d35194 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -276,7 +276,7 @@ QQmlRefPointer<CompiledData::CompilationUnit> FunctionCtor::parse(ExecutionEngin return cg.generateCompilationUnit(); } -ReturnedValue FunctionCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *) +ReturnedValue FunctionCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) { ExecutionEngine *engine = f->engine(); @@ -286,7 +286,14 @@ ReturnedValue FunctionCtor::virtualCallAsConstructor(const FunctionObject *f, co Function *vmf = compilationUnit->linkToEngine(engine); ExecutionContext *global = engine->scriptContext(); - return Encode(FunctionObject::createScriptFunction(global, vmf)); + ReturnedValue o = Encode(FunctionObject::createScriptFunction(global, vmf)); + + if (!newTarget) + return o; + Scope scope(engine); + ScopedObject obj(scope, o); + obj->setProtoFromNewTarget(newTarget); + return obj->asReturnedValue(); } // 15.3.1: This is equivalent to new Function(...) diff --git a/src/qml/jsruntime/qv4generatorobject.cpp b/src/qml/jsruntime/qv4generatorobject.cpp index da87127e08..566db6fd4e 100644 --- a/src/qml/jsruntime/qv4generatorobject.cpp +++ b/src/qml/jsruntime/qv4generatorobject.cpp @@ -54,7 +54,7 @@ void Heap::GeneratorFunctionCtor::init(QV4::ExecutionContext *scope) Heap::FunctionObject::init(scope, QStringLiteral("GeneratorFunction")); } -ReturnedValue GeneratorFunctionCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *) +ReturnedValue GeneratorFunctionCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) { ExecutionEngine *engine = f->engine(); @@ -64,7 +64,14 @@ ReturnedValue GeneratorFunctionCtor::virtualCallAsConstructor(const FunctionObje Function *vmf = compilationUnit->linkToEngine(engine); ExecutionContext *global = engine->scriptContext(); - return Encode(GeneratorFunction::create(global, vmf)); + ReturnedValue o = Encode(GeneratorFunction::create(global, vmf)); + + if (!newTarget) + return o; + Scope scope(engine); + ScopedObject obj(scope, o); + obj->setProtoFromNewTarget(newTarget); + return obj->asReturnedValue(); } // 15.3.1: This is equivalent to new Function(...) diff --git a/src/qml/jsruntime/qv4mapobject.cpp b/src/qml/jsruntime/qv4mapobject.cpp index 7d53b36fcd..68741e7677 100644 --- a/src/qml/jsruntime/qv4mapobject.cpp +++ b/src/qml/jsruntime/qv4mapobject.cpp @@ -59,11 +59,14 @@ void Heap::MapCtor::init(QV4::ExecutionContext *scope) Heap::FunctionObject::init(scope, QStringLiteral("Map")); } -ReturnedValue WeakMapCtor::construct(const FunctionObject *f, const Value *argv, int argc, const Value *, bool weakMap) +ReturnedValue WeakMapCtor::construct(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget, bool weakMap) { Scope scope(f); Scoped<MapObject> a(scope, scope.engine->memoryManager->allocate<MapObject>()); - if (weakMap) { + bool protoSet = false; + if (newTarget) + protoSet = a->setProtoFromNewTarget(newTarget); + if (!protoSet && weakMap) { a->setPrototypeOf(scope.engine->weakMapPrototype()); scope.engine->memoryManager->registerWeakMap(a->d()); } diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp index 11ec53ced5..d26e888069 100644 --- a/src/qml/jsruntime/qv4numberobject.cpp +++ b/src/qml/jsruntime/qv4numberobject.cpp @@ -78,10 +78,18 @@ void Heap::NumberCtor::init(QV4::ExecutionContext *scope) Heap::FunctionObject::init(scope, QStringLiteral("Number")); } -ReturnedValue NumberCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *) +ReturnedValue NumberCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) { + auto v4 = f->engine(); double dbl = argc ? argv[0].toNumber() : 0.; - return Encode(f->engine()->newNumberObject(dbl)); + + ReturnedValue o = Encode(f->engine()->newNumberObject(dbl)); + if (!newTarget) + return o; + Scope scope(v4); + ScopedObject obj(scope, o); + obj->setProtoFromNewTarget(newTarget); + return obj->asReturnedValue(); } ReturnedValue NumberCtor::virtualCall(const FunctionObject *, const Value *, const Value *argv, int argc) diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index a7ede4627c..3d2d54f651 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -986,6 +986,21 @@ const FunctionObject *Object::speciesConstructor(Scope &scope, const FunctionObj return static_cast<const FunctionObject *>(f); } +bool Object::setProtoFromNewTarget(const Value *newTarget) +{ + if (!newTarget || newTarget->isUndefined()) + return false; + + Q_ASSERT(newTarget->isFunctionObject()); + Scope scope(this); + ScopedObject proto(scope, static_cast<const FunctionObject *>(newTarget)->protoProperty()); + if (proto) { + setPrototypeOf(proto); + return true; + } + return false; +} + DEFINE_OBJECT_VTABLE(ArrayObject); diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 6753ebfcd4..ff47810994 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -373,6 +373,8 @@ public: bool isArray() const; const FunctionObject *speciesConstructor(Scope &scope, const FunctionObject *defaultConstructor) const; + bool setProtoFromNewTarget(const Value *newTarget); + protected: static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver,bool *hasProperty); static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver); diff --git a/src/qml/jsruntime/qv4promiseobject.cpp b/src/qml/jsruntime/qv4promiseobject.cpp index a955e5eb6a..8450655334 100644 --- a/src/qml/jsruntime/qv4promiseobject.cpp +++ b/src/qml/jsruntime/qv4promiseobject.cpp @@ -364,7 +364,7 @@ void Heap::RejectWrapper::init() } -ReturnedValue PromiseCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *) +ReturnedValue PromiseCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) { Scope scope(f); @@ -396,6 +396,9 @@ ReturnedValue PromiseCtor::virtualCallAsConstructor(const FunctionObject *f, con a->d()->resolution.set(scope.engine, Value::fromReturnedValue(scope.engine->catchException())); } + if (newTarget) + a->setProtoFromNewTarget(newTarget); + return a->asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 8cdec2f6ee..9344a231ff 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -2226,9 +2226,7 @@ void QmlSignalHandler::initProto(ExecutionEngine *engine) void MultiplyWrappedQObjectMap::insert(QObject *key, Heap::Object *value) { - QV4::WeakValue v; - v.set(value->internalClass->engine, value); - QHash<QObject*, QV4::WeakValue>::insert(key, v); + QHash<QObject*, QV4::WeakValue>::operator[](key).set(value->internalClass->engine, value); connect(key, SIGNAL(destroyed(QObject*)), this, SLOT(removeDestroyedObject(QObject*))); } diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index be46245d5a..6465ee0fa6 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -290,7 +290,14 @@ public: Iterator end() { return QHash<QObject*, QV4::WeakValue>::end(); } void insert(QObject *key, Heap::Object *value); - ReturnedValue value(QObject *key) const { return QHash<QObject*, QV4::WeakValue>::value(key).value(); } + ReturnedValue value(QObject *key) const + { + ConstIterator it = find(key); + return it == end() + ? QV4::WeakValue().value() + : it->value(); + } + Iterator erase(Iterator it); void remove(QObject *key); void mark(QObject *key, MarkStack *markStack); diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 4ef4fa2c9e..9df286065d 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -332,7 +332,13 @@ ReturnedValue RegExpCtor::virtualCallAsConstructor(const FunctionObject *fo, con return scope.engine->throwSyntaxError(QStringLiteral("Invalid regular expression")); } - return Encode(scope.engine->newRegExpObject(regexp)); + ReturnedValue o = Encode(scope.engine->newRegExpObject(regexp)); + + if (!newTarget) + return o; + ScopedObject obj(scope, o); + obj->setProtoFromNewTarget(newTarget); + return obj->asReturnedValue(); } ReturnedValue RegExpCtor::virtualCall(const FunctionObject *f, const Value *, const Value *argv, int argc) diff --git a/src/qml/jsruntime/qv4setobject.cpp b/src/qml/jsruntime/qv4setobject.cpp index 3c9b5031d1..088ecbe30d 100644 --- a/src/qml/jsruntime/qv4setobject.cpp +++ b/src/qml/jsruntime/qv4setobject.cpp @@ -59,11 +59,14 @@ void Heap::SetCtor::init(QV4::ExecutionContext *scope) Heap::FunctionObject::init(scope, QStringLiteral("Set")); } -ReturnedValue WeakSetCtor::construct(const FunctionObject *f, const Value *argv, int argc, const Value *, bool isWeak) +ReturnedValue WeakSetCtor::construct(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget, bool isWeak) { Scope scope(f); Scoped<SetObject> a(scope, scope.engine->memoryManager->allocate<SetObject>()); - if (isWeak) + bool protoSet = false; + if (newTarget) + protoSet = a->setProtoFromNewTarget(newTarget); + if (!protoSet && isWeak) a->setPrototypeOf(scope.engine->weakSetPrototype()); a->d()->isWeakSet = isWeak; diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index 03f351b9e4..d0f6aff9d9 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -170,7 +170,7 @@ void Heap::StringCtor::init(QV4::ExecutionContext *scope) Heap::FunctionObject::init(scope, QStringLiteral("String")); } -ReturnedValue StringCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *) +ReturnedValue StringCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) { ExecutionEngine *v4 = static_cast<const Object *>(f)->engine(); Scope scope(v4); @@ -180,7 +180,13 @@ ReturnedValue StringCtor::virtualCallAsConstructor(const FunctionObject *f, cons else value = v4->newString(); CHECK_EXCEPTION(); - return Encode(v4->newStringObject(value)); + ReturnedValue o = Encode(v4->newStringObject(value)); + + if (!newTarget) + return o; + ScopedObject obj(scope, o); + obj->setProtoFromNewTarget(newTarget); + return obj->asReturnedValue(); } ReturnedValue StringCtor::virtualCall(const FunctionObject *m, const Value *, const Value *argv, int argc) diff --git a/src/qml/qml.pro b/src/qml/qml.pro index a0af11b2da..94717a8f43 100644 --- a/src/qml/qml.pro +++ b/src/qml/qml.pro @@ -7,7 +7,7 @@ qtConfig(qml-network): \ DEFINES += QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES msvc:equals(QT_ARCH, i386): QMAKE_LFLAGS += /BASE:0x66000000 -win32-msvc*:DEFINES *= _CRT_SECURE_NO_WARNINGS +msvc:DEFINES *= _CRT_SECURE_NO_WARNINGS win32:!winrt:LIBS += -lshell32 solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2 @@ -47,7 +47,7 @@ exists("qqml_enable_gcov") { } # QTBUG-55238, disable new optimizer for MSVC 2015/Update 3. -release:win32-msvc*:equals(QT_CL_MAJOR_VERSION, 19):equals(QT_CL_MINOR_VERSION, 00): \ +release:msvc:equals(QT_CL_MAJOR_VERSION, 19):equals(QT_CL_MINOR_VERSION, 00): \ greaterThan(QT_CL_PATCH_VERSION, 24212):QMAKE_CXXFLAGS += -d2SSAOptimizer- QMAKE_DOCS = $$PWD/doc/qtqml.qdocconf diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index bc53b98b5b..e379d416fd 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -511,6 +511,20 @@ QList<QQmlImports::CompositeSingletonReference> QQmlImports::resolvedCompositeSi findCompositeSingletons(set, compositeSingletons, baseUrl()); } + std::stable_sort(compositeSingletons.begin(), compositeSingletons.end(), + [](const QQmlImports::CompositeSingletonReference &lhs, + const QQmlImports::CompositeSingletonReference &rhs) { + if (lhs.prefix != rhs.prefix) + return lhs.prefix < rhs.prefix; + + if (lhs.typeName != rhs.typeName) + return lhs.typeName < rhs.typeName; + + return lhs.majorVersion != rhs.majorVersion + ? lhs.majorVersion < rhs.majorVersion + : lhs.minorVersion < rhs.minorVersion; + }); + return compositeSingletons; } @@ -744,8 +758,10 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt if (majversion >= 0 && minversion >= 0) { QQmlType t = QQmlMetaType::qmlType(type, uri, majversion, minversion); if (t.isValid()) { - if (vmajor) *vmajor = majversion; - if (vminor) *vminor = minversion; + if (vmajor) + *vmajor = majversion; + if (vminor) + *vminor = minversion; if (type_return) *type_return = t; return true; @@ -804,10 +820,13 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt if (candidate != end) { if (!base) // ensure we have a componentUrl componentUrl = resolveLocalUrl(QString(url + candidate->typeName + dotqml_string), candidate->fileName); - int major = vmajor ? *vmajor : -1; - int minor = vminor ? *vminor : -1; QQmlType returnType = fetchOrCreateTypeForUrl(componentUrl, type, isCompositeSingleton, - nullptr, major, minor); + nullptr, candidate->majorVersion, + candidate->minorVersion); + if (vmajor) + *vmajor = candidate->majorVersion; + if (vminor) + *vminor = candidate->minorVersion; if (type_return) *type_return = returnType; return returnType.isValid(); diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 7480475ca7..cb90af4cf0 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2723,10 +2723,6 @@ void QQmlTypeData::resolveTypes() } } - std::stable_sort(m_compositeSingletons.begin(), m_compositeSingletons.end(), [](const TypeReference &lhs, const TypeReference &rhs){ - return lhs.qualifiedName() < rhs.qualifiedName(); - }); - for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = m_typeReferences.constBegin(), end = m_typeReferences.constEnd(); unresolvedRef != end; ++unresolvedRef) { diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index 3cce30aaf6..4d4540bc36 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -343,6 +343,19 @@ void QQuickTextPrivate::updateBaseline(qreal baseline, qreal dy) q->setBaselineOffset(baseline + yoff + q->topPadding()); } +void QQuickTextPrivate::signalSizeChange(const QSizeF &previousSize) +{ + Q_Q(QQuickText); + + if (layedOutTextRect.size() != previousSize) { + emit q->contentSizeChanged(); + if (layedOutTextRect.width() != previousSize.width()) + emit q->contentWidthChanged(layedOutTextRect.width()); + if (layedOutTextRect.height() != previousSize.height()) + emit q->contentHeightChanged(layedOutTextRect.height()); + } +} + void QQuickTextPrivate::updateSize() { Q_Q(QQuickText); @@ -363,6 +376,8 @@ void QQuickTextPrivate::updateSize() qreal hPadding = q->leftPadding() + q->rightPadding(); qreal vPadding = q->topPadding() + q->bottomPadding(); + const QSizeF previousSize = layedOutTextRect.size(); + if (text.isEmpty() && !isLineLaidOutConnected() && fontSizeMode() == QQuickText::FixedSize) { // How much more expensive is it to just do a full layout on an empty string here? // There may be subtle differences in the height and baseline calculations between @@ -379,14 +394,13 @@ void QQuickTextPrivate::updateSize() q->setImplicitSize(hPadding, fontHeight + vPadding); layedOutTextRect = QRectF(0, 0, 0, fontHeight); advance = QSizeF(); - emit q->contentSizeChanged(); + signalSizeChange(previousSize); updateType = UpdatePaintNode; q->update(); return; } QSizeF size(0, 0); - QSizeF previousSize = layedOutTextRect.size(); //setup instance of QTextLayout for all cases other than richtext if (!richText) { @@ -483,13 +497,7 @@ void QQuickTextPrivate::updateSize() } } - - if (layedOutTextRect.size() != previousSize) - emit q->contentSizeChanged(); - if (layedOutTextRect.width() != previousSize.width()) - emit q->contentWidthChanged(layedOutTextRect.width()); - if (layedOutTextRect.height() != previousSize.height()) - emit q->contentHeightChanged(layedOutTextRect.height()); + signalSizeChange(previousSize); updateType = UpdatePaintNode; q->update(); } diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h index fd26d966c8..efa45e0958 100644 --- a/src/quick/items/qquicktext_p_p.h +++ b/src/quick/items/qquicktext_p_p.h @@ -75,6 +75,7 @@ public: void updateBaseline(qreal baseline, qreal dy); void updateSize(); + void signalSizeChange(const QSizeF &previousSize); void updateLayout(); bool determineHorizontalAlignment(); bool setHAlign(QQuickText::HAlignment, bool forceAlign = false); diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index bfc9f4c769..06a0fc396b 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -2044,11 +2044,22 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * int firstDirtyPos = 0; if (nodeIterator != d->textNodeMap.end()) { firstDirtyPos = nodeIterator->startPos(); + // ### this could be optimized if the first and last dirty nodes are not connected + // as the intermediate text nodes would usually only need to be transformed differently. + int lastDirtyPos = firstDirtyPos; + auto it = d->textNodeMap.constEnd(); + while (it != nodeIterator) { + --it; + if (it->dirty()) { + lastDirtyPos = it->startPos(); + break; + } + } do { rootNode->removeChildNode(nodeIterator->textNode()); delete nodeIterator->textNode(); nodeIterator = d->textNodeMap.erase(nodeIterator); - } while (nodeIterator != d->textNodeMap.end() && nodeIterator->dirty()); + } while (nodeIterator != d->textNodeMap.constEnd() && nodeIterator->startPos() <= lastDirtyPos); } // FIXME: the text decorations could probably be handled separately (only updated for affected textFrames) @@ -2090,7 +2101,7 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * QTextCharFormat format = a->formatAccessor(pos); QTextBlock block = textFrame->firstCursorPosition().block(); engine.setCurrentLine(block.layout()->lineForTextPosition(pos - block.position())); - engine.addTextObject(QPointF(0, 0), format, QQuickTextNodeEngine::Unselected, d->document, + engine.addTextObject(block, QPointF(0, 0), format, QQuickTextNodeEngine::Unselected, d->document, pos, textFrame->frameFormat().position()); nodeStart = pos; } else { diff --git a/src/quick/items/qquicktextnode.cpp b/src/quick/items/qquicktextnode.cpp index 13a8219cbd..0dd12207b7 100644 --- a/src/quick/items/qquicktextnode.cpp +++ b/src/quick/items/qquicktextnode.cpp @@ -205,7 +205,7 @@ void QQuickTextNode::addTextDocument(const QPointF &position, QTextDocument *tex QTextBlock block = textFrame->firstCursorPosition().block(); engine.setCurrentLine(block.layout()->lineForTextPosition(pos - block.position())); - engine.addTextObject(rect.topLeft(), format, QQuickTextNodeEngine::Unselected, textDocument, + engine.addTextObject(block, rect.topLeft(), format, QQuickTextNodeEngine::Unselected, textDocument, pos, textFrame->frameFormat().position()); } else { QTextFrame::iterator it = textFrame->begin(); diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp index 9c91ae4896..792aa31a88 100644 --- a/src/quick/items/qquicktextnodeengine.cpp +++ b/src/quick/items/qquicktextnodeengine.cpp @@ -423,10 +423,11 @@ void QQuickTextNodeEngine::addImage(const QRectF &rect, const QImage &image, qre QRectF searchRect = rect; if (layoutPosition == QTextFrameFormat::InFlow) { if (m_currentLineTree.isEmpty()) { + qreal y = m_currentLine.ascent() - ascent; if (m_currentTextDirection == Qt::RightToLeft) - searchRect.moveTopRight(m_position + m_currentLine.rect().topRight() + QPointF(0, 1)); + searchRect.moveTopRight(m_position + m_currentLine.rect().topRight() + QPointF(0, y)); else - searchRect.moveTopLeft(m_position + m_currentLine.position() + QPointF(0,1)); + searchRect.moveTopLeft(m_position + m_currentLine.position() + QPointF(0, y)); } else { const BinaryTreeNode *lastNode = m_currentLineTree.data() + m_currentLineTree.size() - 1; if (lastNode->glyphRun.isRightToLeft()) { @@ -443,7 +444,7 @@ void QQuickTextNodeEngine::addImage(const QRectF &rect, const QImage &image, qre m_hasContents = true; } -void QQuickTextNodeEngine::addTextObject(const QPointF &position, const QTextCharFormat &format, +void QQuickTextNodeEngine::addTextObject(const QTextBlock &block, const QPointF &position, const QTextCharFormat &format, SelectionState selectionState, QTextDocument *textDocument, int pos, QTextFrameFormat::Position layoutPosition) @@ -476,17 +477,23 @@ void QQuickTextNodeEngine::addTextObject(const QPointF &position, const QTextCha } qreal ascent; - QFontMetrics m(format.font()); + QTextLine line = block.layout()->lineForTextPosition(pos); switch (format.verticalAlignment()) { - case QTextCharFormat::AlignMiddle: - ascent = size.height() / 2 - 1; + case QTextCharFormat::AlignTop: + ascent = line.ascent(); break; - case QTextCharFormat::AlignBaseline: - ascent = size.height() - m.descent() - 1; + case QTextCharFormat::AlignMiddle: { + QFontMetrics m(format.font()); + ascent = (size.height() - m.xHeight()) / 2; + break; + } + case QTextCharFormat::AlignBottom: + ascent = size.height() - line.descent(); break; + case QTextCharFormat::AlignBaseline: default: - ascent = size.height() - 1; + ascent = size.height(); } addImage(QRectF(position, size), image, ascent, selectionState, layoutPosition); @@ -1058,7 +1065,7 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText ? QQuickTextNodeEngine::Selected : QQuickTextNodeEngine::Unselected; - addTextObject(QPointF(), charFormat, selectionState, textDocument, textPos); + addTextObject(block, QPointF(), charFormat, selectionState, textDocument, textPos); } textPos += text.length(); } else { diff --git a/src/quick/items/qquicktextnodeengine_p.h b/src/quick/items/qquicktextnodeengine_p.h index 18c624513a..49c1766045 100644 --- a/src/quick/items/qquicktextnodeengine_p.h +++ b/src/quick/items/qquicktextnodeengine_p.h @@ -179,7 +179,7 @@ public: const QVarLengthArray<QTextLayout::FormatRange> &colorChanges, int textPos, int fragmentEnd, int selectionStart, int selectionEnd); - void addTextObject(const QPointF &position, const QTextCharFormat &format, + void addTextObject(const QTextBlock &block, const QPointF &position, const QTextCharFormat &format, SelectionState selectionState, QTextDocument *textDocument, int pos, QTextFrameFormat::Position layoutPosition = QTextFrameFormat::InFlow); diff --git a/src/quick/quick.pro b/src/quick/quick.pro index 4db614d335..37d2ad1172 100644 --- a/src/quick/quick.pro +++ b/src/quick/quick.pro @@ -5,7 +5,7 @@ qtConfig(qml-network): \ QT_PRIVATE += network DEFINES += QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES -win32-msvc*:DEFINES *= _CRT_SECURE_NO_WARNINGS +msvc:DEFINES *= _CRT_SECURE_NO_WARNINGS solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2 win32:!winrt: LIBS += -luser32 diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations index 02cb6acf99..ed5060a77d 100644 --- a/tests/auto/qml/ecmascripttests/TestExpectations +++ b/tests/auto/qml/ecmascripttests/TestExpectations @@ -139,7 +139,6 @@ built-ins/Date/prototype/toTimeString/invalid-date.js fails built-ins/Date/prototype/toUTCString/day-names.js fails built-ins/Date/prototype/toUTCString/format.js fails built-ins/Date/prototype/toUTCString/month-names.js fails -built-ins/Date/subclassing.js fails built-ins/Function/internals/Construct/base-ctor-revoked-proxy.js fails built-ins/Function/prototype/bind/BoundFunction_restricted-properties.js fails built-ins/Function/prototype/bind/instance-name-chained.js fails @@ -177,14 +176,10 @@ built-ins/Object/prototype/toString/proxy-function.js fails built-ins/Object/prototype/valueOf/S15.2.4.4_A14.js fails built-ins/Object/values/getter-adding-key.js fails built-ins/Object/values/observable-operations.js fails -built-ins/Promise/all/ctx-ctor.js fails built-ins/Promise/prototype/catch/this-value-obj-coercible.js fails -built-ins/Promise/prototype/then/capability-executor-called-twice.js fails built-ins/Promise/prototype/then/capability-executor-not-callable.js fails built-ins/Promise/prototype/then/ctor-custom.js fails built-ins/Promise/race/ctx-ctor.js fails -built-ins/Promise/reject/ctx-ctor.js fails -built-ins/Promise/resolve/ctx-ctor.js fails built-ins/Proxy/ownKeys/return-duplicate-entries-throws.js fails built-ins/Proxy/ownKeys/return-duplicate-symbol-entries-throws.js fails built-ins/RegExp/S15.10.2.12_A2_T1.js fails diff --git a/tests/auto/qml/qmlplugindump/data/dumper/CompositeWithinSingleton/Composite.qml b/tests/auto/qml/qmlplugindump/data/dumper/CompositeWithinSingleton/Composite.qml new file mode 100644 index 0000000000..b1055b6992 --- /dev/null +++ b/tests/auto/qml/qmlplugindump/data/dumper/CompositeWithinSingleton/Composite.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +QtObject { + property int test: 0 +} diff --git a/tests/auto/qml/qmlplugindump/data/dumper/CompositeWithinSingleton/Singleton.qml b/tests/auto/qml/qmlplugindump/data/dumper/CompositeWithinSingleton/Singleton.qml new file mode 100644 index 0000000000..e81b2b6cb5 --- /dev/null +++ b/tests/auto/qml/qmlplugindump/data/dumper/CompositeWithinSingleton/Singleton.qml @@ -0,0 +1,6 @@ +pragma Singleton +import QtQuick 2.0 + +QtObject { + property Composite test: Composite {} +} diff --git a/tests/auto/qml/qmlplugindump/data/dumper/CompositeWithinSingleton/qmldir b/tests/auto/qml/qmlplugindump/data/dumper/CompositeWithinSingleton/qmldir new file mode 100644 index 0000000000..5a9cb1bd96 --- /dev/null +++ b/tests/auto/qml/qmlplugindump/data/dumper/CompositeWithinSingleton/qmldir @@ -0,0 +1,4 @@ +module dumper.CompositeWithinSingleton +singleton Singleton 1.0 Singleton.qml +Composite 1.0 Composite.qml +depends QtQuick 2.0 diff --git a/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp b/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp index f673fca1d7..17766a89b5 100644 --- a/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp +++ b/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp @@ -45,6 +45,8 @@ private slots: void initTestCase(); void builtins(); void singleton(); + void compositeWithinSingleton(); + void plugin_data(); void plugin(); @@ -118,6 +120,21 @@ void tst_qmlplugindump::singleton() QVERIFY2(result.contains(QLatin1String("exportMetaObjectRevisions: [0]")), qPrintable(result)); } +void tst_qmlplugindump::compositeWithinSingleton() +{ + QProcess dumper; + QStringList args; + args << QLatin1String("dumper.CompositeWithinSingleton") << QLatin1String("1.0") + << QLatin1String(QT_QMLTEST_DIR "/data"); + dumper.start(qmlplugindumpPath, args); + QVERIFY2(dumper.waitForStarted(), qPrintable(dumper.errorString())); + QVERIFY2(dumper.waitForFinished(), qPrintable(dumper.errorString())); + + const QString &result = dumper.readAllStandardOutput(); + QVERIFY2(result.contains(QLatin1String("exports: [\"Composite 1.0\"]")), qPrintable(result)); + QVERIFY2(result.contains(QLatin1String("exportMetaObjectRevisions: [0]")), qPrintable(result)); +} + void tst_qmlplugindump::plugin_data() { QTest::addColumn<QString>("import"); diff --git a/tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton1.qml b/tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton1.qml new file mode 100644 index 0000000000..f4ad5e5f7a --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton1.qml @@ -0,0 +1,6 @@ +pragma Singleton +import QtQuick 2.0 + +Item { + property bool ok: true +} diff --git a/tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton2.qml b/tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton2.qml new file mode 100644 index 0000000000..55dd57517f --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton2.qml @@ -0,0 +1,7 @@ +pragma Singleton +import QtQuick 2.0 +import cppsingletonmodule 1.0 + +Item { + property bool ok: CppRegisteredSingleton1.ok +} diff --git a/tests/auto/qml/qqmltypeloader/data/Singleton.qml b/tests/auto/qml/qqmltypeloader/data/Singleton.qml new file mode 100644 index 0000000000..3a1b1c1493 --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/Singleton.qml @@ -0,0 +1,7 @@ +pragma Singleton +import QtQml 2.0 +import modulewithsingleton 1.0 + +QtObject { + property bool ok: true +} diff --git a/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton1.qml b/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton1.qml new file mode 100644 index 0000000000..34eca59f86 --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton1.qml @@ -0,0 +1,7 @@ +pragma Singleton +import QtQuick 2.0 +import "." + +Item { + property bool ok: true +} diff --git a/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton2.qml b/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton2.qml new file mode 100644 index 0000000000..607d85d7fb --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton2.qml @@ -0,0 +1,7 @@ +pragma Singleton +import QtQuick 2.0 +import "." + +Item { + property bool ok: Singleton1.ok +} diff --git a/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/qmldir b/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/qmldir new file mode 100644 index 0000000000..71b889a12d --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/qmldir @@ -0,0 +1,2 @@ +singleton Singleton1 1.0 Singleton1.qml +singleton Singleton2 1.0 Singleton2.qml diff --git a/tests/auto/qml/qqmltypeloader/data/multisingletonuser.qml b/tests/auto/qml/qqmltypeloader/data/multisingletonuser.qml new file mode 100644 index 0000000000..b80e2c5223 --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/multisingletonuser.qml @@ -0,0 +1,7 @@ +import QtQml 2.0 +import multisingletonmodule 1.0 +import cppsingletonmodule 1.0 + +QtObject { + property bool ok: Singleton2.ok && CppRegisteredSingleton2.ok +} diff --git a/tests/auto/qml/qqmltypeloader/data/singletonuser.qml b/tests/auto/qml/qqmltypeloader/data/singletonuser.qml new file mode 100644 index 0000000000..79ca47e12f --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/singletonuser.qml @@ -0,0 +1,6 @@ +import QtQml 2.0 +import modulewithsingleton 1.0 + +QtObject { + property bool ok: Singleton.ok +} diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp index cf3bc8b050..3745fad470 100644 --- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp +++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp @@ -31,6 +31,9 @@ #include <QtQml/qqmlnetworkaccessmanagerfactory.h> #include <QtQuick/qquickview.h> #include <QtQuick/qquickitem.h> +#if QT_CONFIG(process) +#include <QtCore/qprocess.h> +#endif #include <QtQml/private/qqmlengine_p.h> #include <QtQml/private/qqmltypeloader_p.h> #include "../../shared/testhttpserver.h" @@ -50,6 +53,8 @@ private slots: void keepRegistrations(); void intercept(); void redirect(); + void qmlSingletonWithinModule(); + void multiSingletonModule(); }; void tst_QQMLTypeLoader::testLoadComplete() @@ -428,6 +433,57 @@ void tst_QQMLTypeLoader::redirect() QTRY_COMPARE(object->property("xy").toInt(), 323232); } +void tst_QQMLTypeLoader::qmlSingletonWithinModule() +{ + qmlClearTypeRegistrations(); + QQmlEngine engine; + qmlRegisterSingletonType(testFileUrl("Singleton.qml"), "modulewithsingleton", 1, 0, "Singleton"); + + QQmlComponent component(&engine, testFileUrl("singletonuser.qml")); + QCOMPARE(component.status(), QQmlComponent::Ready); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QVERIFY(obj->property("ok").toBool()); +} + +void tst_QQMLTypeLoader::multiSingletonModule() +{ + qmlClearTypeRegistrations(); + QQmlEngine engine; + engine.addImportPath(testFile("imports")); + + qmlRegisterSingletonType(testFileUrl("CppRegisteredSingleton1.qml"), "cppsingletonmodule", + 1, 0, "CppRegisteredSingleton1"); + qmlRegisterSingletonType(testFileUrl("CppRegisteredSingleton2.qml"), "cppsingletonmodule", + 1, 0, "CppRegisteredSingleton2"); + + QQmlComponent component(&engine, testFileUrl("multisingletonuser.qml")); + QCOMPARE(component.status(), QQmlComponent::Ready); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QVERIFY(obj->property("ok").toBool()); + +#if QT_CONFIG(process) + const char *skipKey = "QT_TST_QQMLTYPELOADER_SKIP_MISMATCH"; + if (qEnvironmentVariableIsSet(skipKey)) + return; + for (int i = 0; i < 5; ++i) { + QProcess child; + child.setProgram(QCoreApplication::applicationFilePath()); + child.setArguments(QStringList(QLatin1String("multiSingletonModule"))); + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert(QLatin1String("QT_LOGGING_RULES"), QLatin1String("qt.qml.diskcache.debug=true")); + env.insert(QLatin1String(skipKey), QLatin1String("1")); + child.setProcessEnvironment(env); + child.start(); + QVERIFY(child.waitForFinished()); + QCOMPARE(child.exitCode(), 0); + QVERIFY(!child.readAllStandardOutput().contains("Checksum mismatch for cached version")); + QVERIFY(!child.readAllStandardError().contains("Checksum mismatch for cached version")); + } +#endif +} + QTEST_MAIN(tst_QQMLTypeLoader) #include "tst_qqmltypeloader.moc" diff --git a/tests/auto/qml/qv4mm/tst_qv4mm.cpp b/tests/auto/qml/qv4mm/tst_qv4mm.cpp index 07f8e9f1d1..d8f4ed12e8 100644 --- a/tests/auto/qml/qv4mm/tst_qv4mm.cpp +++ b/tests/auto/qml/qv4mm/tst_qv4mm.cpp @@ -30,6 +30,7 @@ #include <QQmlEngine> #include <QLoggingCategory> #include <private/qv4mm_p.h> +#include <private/qv4qobjectwrapper_p.h> class tst_qv4mm : public QObject { @@ -37,6 +38,7 @@ class tst_qv4mm : public QObject private slots: void gcStats(); + void multiWrappedQObjects(); }; void tst_qv4mm::gcStats() @@ -46,6 +48,44 @@ void tst_qv4mm::gcStats() engine.collectGarbage(); } +void tst_qv4mm::multiWrappedQObjects() +{ + QV4::ExecutionEngine engine1; + QV4::ExecutionEngine engine2; + { + QObject object; + for (int i = 0; i < 10; ++i) + QV4::QObjectWrapper::wrap(i % 2 ? &engine1 : &engine2, &object); + + QCOMPARE(engine1.memoryManager->m_pendingFreedObjectWrapperValue.size(), 0); + QCOMPARE(engine2.memoryManager->m_pendingFreedObjectWrapperValue.size(), 0); + { + QV4::WeakValue value; + value.set(&engine1, QV4::QObjectWrapper::wrap(&engine1, &object)); + } + + QCOMPARE(engine1.memoryManager->m_pendingFreedObjectWrapperValue.size(), 1); + QCOMPARE(engine2.memoryManager->m_pendingFreedObjectWrapperValue.size(), 0); + + // Moves the additional WeakValue from m_multiplyWrappedQObjects to + // m_pendingFreedObjectWrapperValue. It's still alive after all. + engine1.memoryManager->runGC(); + QCOMPARE(engine1.memoryManager->m_pendingFreedObjectWrapperValue.size(), 2); + + // engine2 doesn't own the object as engine1 was the first to wrap it above. + // Therefore, no effect here. + engine2.memoryManager->runGC(); + QCOMPARE(engine2.memoryManager->m_pendingFreedObjectWrapperValue.size(), 0); + } + + // Clears m_pendingFreedObjectWrapperValue. Now it's really dead. + engine1.memoryManager->runGC(); + QCOMPARE(engine1.memoryManager->m_pendingFreedObjectWrapperValue.size(), 0); + + engine2.memoryManager->runGC(); + QCOMPARE(engine2.memoryManager->m_pendingFreedObjectWrapperValue.size(), 0); +} + QTEST_MAIN(tst_qv4mm) #include "tst_qv4mm.moc" diff --git a/tests/auto/qml/v4misc/tst_v4misc.cpp b/tests/auto/qml/v4misc/tst_v4misc.cpp index 5aac91aae9..ecc3a4100c 100644 --- a/tests/auto/qml/v4misc/tst_v4misc.cpp +++ b/tests/auto/qml/v4misc/tst_v4misc.cpp @@ -40,6 +40,9 @@ private slots: void parserMisc_data(); void parserMisc(); + + void subClassing_data(); + void subClassing(); }; void tst_v4misc::tdzOptimizations_data() @@ -130,6 +133,46 @@ void tst_v4misc::parserMisc() QCOMPARE(result.toString(), error); } +void tst_v4misc::subClassing_data() +{ + QTest::addColumn<QString>("script"); + + QString code( + "class Foo extends %1 {" + " constructor() { super(); this.reset(); }" + " reset() { }" + "}" + "new Foo();"); + + + QTest::newRow("Array") << code.arg("Array"); + QTest::newRow("Boolean") << code.arg("Boolean"); + QTest::newRow("Date") << code.arg("Date"); + QTest::newRow("Function") << code.arg("Function"); + QTest::newRow("Number") << code.arg("Number"); + QTest::newRow("Map") << code.arg("Map"); + QTest::newRow("Promise") << QString( + "class Foo extends Promise {" + " constructor() { super(Function()); this.reset(); }" + " reset() { }" + "}" + "new Foo();"); + QTest::newRow("RegExp") << code.arg("RegExp"); + QTest::newRow("Set") << code.arg("Set"); + QTest::newRow("String") << code.arg("String"); + QTest::newRow("WeakMap") << code.arg("WeakMap"); + QTest::newRow("WeakSet") << code.arg("WeakSet"); +} + +void tst_v4misc::subClassing() +{ + QFETCH(QString, script); + + QJSEngine engine; + QJSValue result = engine.evaluate(script); + QVERIFY(!result.isError()); +} + QTEST_MAIN(tst_v4misc); #include "tst_v4misc.moc" diff --git a/tests/auto/quick/qquicktext/data/contentHeight.qml b/tests/auto/quick/qquicktext/data/contentHeight.qml new file mode 100644 index 0000000000..472e97078e --- /dev/null +++ b/tests/auto/quick/qquicktext/data/contentHeight.qml @@ -0,0 +1,7 @@ +import QtQuick 2.9 + +Text{ + width: 200 + height: contentHeight + text: '' +} diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp index d8ff2f6e13..fd0ba0f49b 100644 --- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp @@ -160,6 +160,8 @@ private slots: void fontInfo(); + void initialContentHeight(); + private: QStringList standard; QStringList richText; @@ -4384,6 +4386,18 @@ void tst_qquicktext::fontInfo() QVERIFY(copy->font().pixelSize() < 1000); } +void tst_qquicktext::initialContentHeight() +{ + QQmlComponent component(&engine, testFile("contentHeight.qml")); + QVERIFY(component.isReady()); + QScopedPointer<QObject> object(component.create()); + QObject *root = object.data(); + QVERIFY(root); + QQuickText *text = qobject_cast<QQuickText *>(root); + QVERIFY(text); + QCOMPARE(text->height(), text->contentHeight()); +} + void tst_qquicktext::implicitSizeChangeRewrap() { QScopedPointer<QQuickView> window(new QQuickView); diff --git a/tools/qmlscene/main.cpp b/tools/qmlscene/main.cpp index 1372bd3751..5190368e20 100644 --- a/tools/qmlscene/main.cpp +++ b/tools/qmlscene/main.cpp @@ -310,14 +310,6 @@ static void displayFileDialog(Options *options) puts("No filename specified..."); } -#if QT_CONFIG(translation) -static void loadTranslationFile(QTranslator &translator, const QString& directory) -{ - translator.load(QLocale(), QLatin1String("qml"), QLatin1String("_"), directory + QLatin1String("/i18n")); - QCoreApplication::installTranslator(&translator); -} -#endif - static void loadDummyDataFiles(QQmlEngine &engine, const QString& directory) { QDir dir(directory+"/dummydata", "*.qml"); @@ -588,10 +580,6 @@ int main(int argc, char ** argv) if (!options.url.isEmpty()) { if (!options.versionDetection || checkVersion(options.url)) { -#if QT_CONFIG(translation) - QTranslator translator; -#endif - // TODO: as soon as the engine construction completes, the debug service is // listening for connections. But actually we aren't ready to debug anything. QQmlEngine engine; @@ -603,7 +591,9 @@ int main(int argc, char ** argv) if (options.url.isLocalFile()) { QFileInfo fi(options.url.toLocalFile()); #if QT_CONFIG(translation) - loadTranslationFile(translator, fi.path()); + QTranslator *translator = new QTranslator(app.get()); + if (translator->load(QLocale(), QLatin1String("qml"), QLatin1String("_"), fi.path() + QLatin1String("/i18n"))) + QCoreApplication::installTranslator(translator); #endif loadDummyDataFiles(engine, fi.path()); } |