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 /src | |
parent | b799e061a3cbf995ac7c88b315f5916e3a687162 (diff) | |
parent | 5246b910771e0dd824b4eea7c5245e5f9f3a63f0 (diff) |
Merge remote-tracking branch 'origin/5.12' into dev
Change-Id: I57e4b762dcccf2f7f6e4b659f6fc8c40465d3322
Diffstat (limited to 'src')
30 files changed, 205 insertions, 69 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 |