aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/imports/wavefrontmesh/qwavefrontmesh.cpp13
-rw-r--r--src/qml/doc/src/cppintegration/definetypes.qdoc4
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc3
-rw-r--r--src/qml/jsruntime/qv4promiseobject.cpp201
-rw-r--r--src/qml/jsruntime/qv4promiseobject_p.h7
-rw-r--r--src/qml/qml/qqmlimport.cpp13
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp12
-rw-r--r--src/quick/doc/images/sg-renderloop-singlethreaded.jpgbin29515 -> 0 bytes
-rw-r--r--src/quick/doc/images/sg-renderloop-singlethreaded.pngbin0 -> 162831 bytes
-rw-r--r--src/quick/doc/images/sg-renderloop-threaded.jpgbin45262 -> 0 bytes
-rw-r--r--src/quick/doc/images/sg-renderloop-threaded.pngbin0 -> 225933 bytes
-rw-r--r--src/quick/doc/images/sg-renderloop-threaded.xml2
-rw-r--r--src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc4
-rw-r--r--src/quick/handlers/qquickhandlerpoint.cpp15
-rw-r--r--src/quick/handlers/qquickhoverhandler.cpp3
-rw-r--r--src/quick/handlers/qquickpointerdevicehandler.cpp5
-rw-r--r--src/quick/handlers/qquicksinglepointhandler.cpp3
-rw-r--r--src/quick/handlers/qquicktaphandler.cpp9
-rw-r--r--src/quick/items/qquickevents.cpp10
-rw-r--r--src/quick/items/qquickitemview.cpp3
-rw-r--r--src/quick/items/qquickshadereffectmesh_p.h4
-rw-r--r--src/quick/items/qquickwindow.cpp6
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode.cpp2
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.cpp31
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p_p.h7
-rw-r--r--tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp2
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp15
-rw-r--r--tests/auto/qml/qqmlimport/data/QTBUG-77102/imports/MyPlugin/MyComponent_0_9.qml14
-rw-r--r--tests/auto/qml/qqmlimport/data/QTBUG-77102/imports/MyPlugin/MyComponent_1_0.qml15
-rw-r--r--tests/auto/qml/qqmlimport/data/QTBUG-77102/imports/MyPlugin/MySettings_1_0.qml7
-rw-r--r--tests/auto/qml/qqmlimport/data/QTBUG-77102/imports/MyPlugin/qmldir6
-rw-r--r--tests/auto/qml/qqmlimport/data/QTBUG-77102/main.0.9.fail.qml11
-rw-r--r--tests/auto/qml/qqmlimport/data/QTBUG-77102/main.0.9.qml11
-rw-r--r--tests/auto/qml/qqmlimport/data/QTBUG-77102/main.1.0.qml11
-rw-r--r--tests/auto/qml/qqmlimport/data/QTBUG-77102/main.nonumber.qml11
-rw-r--r--tests/auto/qml/qqmlimport/tst_qqmlimport.cpp45
-rw-r--r--tests/auto/qml/qqmlpromise/data/promisechain.qml24
-rw-r--r--tests/auto/qml/qqmlpromise/tst_qqmlpromise.cpp15
-rw-r--r--tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/dragParentOfMPTA.qml50
-rw-r--r--tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp43
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp82
-rw-r--r--tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml2
-rw-r--r--tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp8
-rw-r--r--tests/auto/quick/qquickflickable/tst_qquickflickable.cpp3
-rw-r--r--tests/auto/quick/qquicklistview/data/resizeAfterComponentComplete.qml77
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp16
46 files changed, 693 insertions, 132 deletions
diff --git a/src/imports/wavefrontmesh/qwavefrontmesh.cpp b/src/imports/wavefrontmesh/qwavefrontmesh.cpp
index 101e6ab4b0..e973ef0103 100644
--- a/src/imports/wavefrontmesh/qwavefrontmesh.cpp
+++ b/src/imports/wavefrontmesh/qwavefrontmesh.cpp
@@ -53,19 +53,6 @@
QT_BEGIN_NAMESPACE
-static const char qt_position_attribute_name[] = "qt_Vertex";
-static const char qt_texcoord_attribute_name[] = "qt_MultiTexCoord0";
-
-const char *qtPositionAttributeName()
-{
- return qt_position_attribute_name;
-}
-
-const char *qtTexCoordAttributeName()
-{
- return qt_texcoord_attribute_name;
-}
-
class QWavefrontMeshPrivate : public QObjectPrivate
{
public:
diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc
index 41bc9fd140..2e8102bd65 100644
--- a/src/qml/doc/src/cppintegration/definetypes.qdoc
+++ b/src/qml/doc/src/cppintegration/definetypes.qdoc
@@ -471,7 +471,7 @@ will be accessible to the \e attachee:
class MessageBoardAttachedType : public QObject
{
Q_OBJECT
- Q_PROPERTY(bool expired READ expired WRITE expired NOTIFY expiredChanged)
+ Q_PROPERTY(bool expired READ expired WRITE setExpired NOTIFY expiredChanged)
public:
MessageBoardAttachedType(QObject *parent);
bool expired() const;
@@ -493,7 +493,7 @@ class MessageBoard : public QObject
{
Q_OBJECT
public:
- static MessageBoard *qmlAttachedProperties(QObject *object)
+ static MessageBoardAttachedType *qmlAttachedProperties(QObject *object)
{
return new MessageBoardAttachedType(object);
}
diff --git a/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc b/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
index a5ad6af4a2..e607666886 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
@@ -128,6 +128,9 @@ loops - it could indicate that the binding is being used for more than describin
property relationships. Complex bindings can reduce code performance, readability,
and maintainability. It may be a good idea to redesign components that have
complex bindings, or at least factor the binding out into a separate function.
+As a general rule, users should not rely on the evaluation order of bindings.
+
+\sa {Positioning with Anchors}
\target qml-javascript-assignment
diff --git a/src/qml/jsruntime/qv4promiseobject.cpp b/src/qml/jsruntime/qv4promiseobject.cpp
index b32e227b58..27075e96a0 100644
--- a/src/qml/jsruntime/qv4promiseobject.cpp
+++ b/src/qml/jsruntime/qv4promiseobject.cpp
@@ -86,6 +86,7 @@ namespace QV4 {
namespace Promise {
const int PROMISE_REACTION_EVENT = QEvent::registerEventType();
+const int PROMISE_RESOLVE_THENABLE_EVENT = QEvent::registerEventType();
struct ReactionEvent : public QEvent
{
@@ -99,6 +100,18 @@ struct ReactionEvent : public QEvent
QV4::PersistentValue resolution;
};
+struct ResolveThenableEvent : public QEvent
+{
+ ResolveThenableEvent(ExecutionEngine *e, const PromiseObject *promise_, const Object *thenable_, const FunctionObject *then_)
+ : QEvent(QEvent::Type(PROMISE_RESOLVE_THENABLE_EVENT)), promise(e, *promise_), thenable(e, *thenable_), then(e, *then_)
+ {}
+
+ QV4::PersistentValue promise;
+ QV4::PersistentValue thenable;
+ QV4::PersistentValue then;
+};
+
+
} // namespace Promise
} // namespace QV4
QT_END_NAMESPACE
@@ -115,6 +128,11 @@ void ReactionHandler::addReaction(ExecutionEngine *e, const Value *reaction, con
QCoreApplication::postEvent(this, new ReactionEvent(e, reaction, value));
}
+void ReactionHandler::addResolveThenable(ExecutionEngine *e, const PromiseObject *promise, const Object *thenable, const FunctionObject *then)
+{
+ QCoreApplication::postEvent(this, new ResolveThenableEvent(e, promise, thenable, then));
+}
+
void ReactionHandler::customEvent(QEvent *event)
{
if (event)
@@ -122,6 +140,9 @@ void ReactionHandler::customEvent(QEvent *event)
const int type = event->type();
if (type == PROMISE_REACTION_EVENT)
executeReaction(static_cast<ReactionEvent*>(event));
+
+ if (type == PROMISE_RESOLVE_THENABLE_EVENT)
+ executeResolveThenable(static_cast<ResolveThenableEvent*>(event));
}
}
@@ -159,6 +180,7 @@ void ReactionHandler::executeReaction(ReactionEvent *event)
}
}
+
namespace {
class FunctionBuilder {
@@ -200,6 +222,26 @@ public:
}
+
+void ReactionHandler::executeResolveThenable(ResolveThenableEvent *event)
+{
+ Scope scope(event->then.engine());
+ JSCallData jsCallData(scope, 2);
+ PromiseObject *promise = event->promise.as<PromiseObject>();
+ ScopedFunctionObject resolve {scope, FunctionBuilder::makeResolveFunction(scope.engine, promise->d())};
+ ScopedFunctionObject reject {scope, FunctionBuilder::makeRejectFunction(scope.engine, promise->d())};
+ jsCallData->args[0] = resolve;
+ jsCallData.args[1] = reject;
+ jsCallData->thisObject = event->thenable.as<QV4::Object>();
+ event->then.as<const FunctionObject>()->call(jsCallData);
+ if (scope.engine->hasException) {
+ JSCallData rejectCallData(scope, 1);
+ rejectCallData->args[0] = scope.engine->catchException();
+ Scoped<RejectWrapper> reject {scope, scope.engine->memoryManager->allocate<QV4::RejectWrapper>()};
+ reject->call(rejectCallData);
+ }
+}
+
void Heap::PromiseObject::setState(PromiseObject::State state)
{
this->state = state;
@@ -363,23 +405,36 @@ void Heap::RejectWrapper::init()
Heap::FunctionObject::init();
}
+ReturnedValue PromiseCtor::virtualCall(const FunctionObject *f, const Value *, const Value *, int)
+{
+ // 25.4.3.1 Promise ( executor )
+ // 1. If NewTarget is undefined, throw a TypeError exception.
+ Scope scope(f);
+ THROW_TYPE_ERROR();
+}
ReturnedValue PromiseCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
{
+ // 25.4.3.1 Promise ( executor )
+
Scope scope(f);
- if (argc != 1)
+ if (argc == 0) // If there are no arguments, argument 1 will be undefined ==> thus not callable ==> type error
THROW_TYPE_ERROR();
ScopedFunctionObject executor(scope, argv[0].as<const FunctionObject>());
- if (!executor)
- THROW_TYPE_ERROR();
+ if (!executor) //2. If IsCallable(executor) is false
+ THROW_TYPE_ERROR(); // throw a TypeError exception
Scoped<PromiseObject> a(scope, scope.engine->newPromiseObject());
if (scope.engine->hasException)
return Encode::undefined();
- a->d()->state = Heap::PromiseObject::Pending;
+ a->d()->state = Heap::PromiseObject::Pending; //4. Set promise.[[PromiseState]] to "pending"
+ // 5. Set promise.[[PromiseFulfillReactions]] to a new empty List.
+ // 6. Set promise.[[PromiseRejectReactions]] to a new empty List.
+ // 7. Set promise.[[PromiseIsHandled]] to false.
+ // happens in constructor of a
ScopedFunctionObject resolve(scope, FunctionBuilder::makeResolveFunction(scope.engine, a->d()));
ScopedFunctionObject reject(scope, FunctionBuilder::makeRejectFunction(scope.engine, a->d()));
@@ -387,13 +442,15 @@ ReturnedValue PromiseCtor::virtualCallAsConstructor(const FunctionObject *f, con
JSCallData jsCallData(scope, 2);
jsCallData->args[0] = resolve;
jsCallData->args[1] = reject;
- jsCallData->thisObject = a;
+ //jsCallData->thisObject = a; VERIFY corretness, but this should be undefined (see below)
- executor->call(jsCallData);
+ executor->call(jsCallData); // 9. Let completion be Call(executor, undefined, « resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]] »).
if (scope.engine->hasException) {
- a->d()->state = Heap::PromiseObject::Rejected;
- a->d()->resolution.set(scope.engine, Value::fromReturnedValue(scope.engine->catchException()));
+ ScopedValue exception {scope, scope.engine->catchException()};
+ JSCallData callData {scope, 1};
+ callData.args[0] = exception;
+ reject->call(callData);
}
if (newTarget)
@@ -402,42 +459,42 @@ ReturnedValue PromiseCtor::virtualCallAsConstructor(const FunctionObject *f, con
return a->asReturnedValue();
}
-ReturnedValue PromiseCtor::virtualCall(const FunctionObject *f, const Value *, const Value *, int)
-{
- Scope scope(f);
- THROW_TYPE_ERROR();
-}
ReturnedValue PromiseCtor::method_resolve(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
{
+ // 25.4.4.5Promise.resolve ( x )
Scope scope(f);
ExecutionEngine* e = scope.engine;
- if (!thisObject || !thisObject->isObject())
+ if (!thisObject || !thisObject->isObject()) // 2. If Type(C) is not Object, throw a TypeError exception
THROW_TYPE_ERROR();
- ScopedValue argument(scope);
+ ScopedValue x(scope);
if (argc < 1) {
- argument = Encode::undefined();
+ x = Encode::undefined();
} else {
- argument = argv[0];
+ x = argv[0];
}
- if (isPromise(argument) && argument->isObject()) {
+ // 3. If IsPromise(x) is true, then
+ if (isPromise(x) && x->isObject()) {
ScopedObject so(scope, thisObject);
- ScopedObject constructor(scope, argument->objectValue()->get(e->id_constructor()));
- if (so->d() == constructor->d())
- return argument->asReturnedValue();
+ // Let xConstructor be ? Get(x, "constructor").
+ ScopedObject constructor(scope, x->objectValue()->get(e->id_constructor()));
+ if (so->d() == constructor->d()) // If SameValue(xConstructor, C) is true, return x.
+ return x->asReturnedValue();
}
+ // Let promiseCapability be ? NewPromiseCapability(C).
Scoped<PromiseCapability> capability(scope, e->memoryManager->allocate<QV4::PromiseCapability>());
ScopedObject newPromise(scope, e->newPromiseObject(thisObject->as<const FunctionObject>(), capability));
if (!newPromise || !isCallable(capability->d()->resolve) || !isCallable(capability->d()->reject))
THROW_TYPE_ERROR();
+ // Perform ? Call(promiseCapability.[[Resolve]], undefined, « x »).
ScopedValue undefined(scope, Value::undefinedValue());
ScopedFunctionObject resolve(scope, capability->d()->resolve);
- resolve->call(undefined, argument, 1);
+ resolve->call(undefined, x, 1);
return newPromise.asReturnedValue();
}
@@ -447,16 +504,18 @@ ReturnedValue PromiseCtor::method_reject(const FunctionObject *f, const Value *t
Scope scope(f);
ExecutionEngine *e = scope.engine;
+ // 2. If Type(C) is not Object, throw a TypeError exception.
if (!thisObject || !thisObject->isObject())
THROW_TYPE_ERROR();
- ScopedValue argument(scope);
+ ScopedValue r(scope);
if (argc < 1) {
- argument = Encode::undefined();
+ r = Encode::undefined();
} else {
- argument = argv[0];
+ r = argv[0];
}
+ // 3. Let promiseCapability be ? NewPromiseCapability(C).
Scoped<PromiseCapability> capability(scope, e->memoryManager->allocate<QV4::PromiseCapability>());
ScopedObject newPromise(scope, e->newPromiseObject(thisObject->as<const FunctionObject>(), capability));
@@ -465,7 +524,8 @@ ReturnedValue PromiseCtor::method_reject(const FunctionObject *f, const Value *t
ScopedValue undefined(scope, Value::undefinedValue());
ScopedFunctionObject reject(scope, capability->d()->reject.as<const FunctionObject>());
- reject->call(undefined, argument, 1);
+ // Perform ? Call(promiseCapability.[[Reject]], undefined, « r »).
+ reject->call(undefined, r, 1);
return newPromise.asReturnedValue();
}
@@ -475,6 +535,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this
Scope scope(f);
ExecutionEngine* e = scope.engine;
+ // 2. If Type(C) is not Object, throw a TypeError exception.
if (!thisObject || !thisObject->isObject())
THROW_TYPE_ERROR();
@@ -777,6 +838,7 @@ void PromisePrototype::init(ExecutionEngine *engine, Object *ctor)
ReturnedValue PromisePrototype::method_then(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
{
+ // 25.4.5.3 Promise.prototype.then
Scope scope(f);
ExecutionEngine* e = scope.engine;
@@ -804,6 +866,7 @@ ReturnedValue PromisePrototype::method_then(const FunctionObject *f, const Value
if (!constructor || scope.hasException())
THROW_TYPE_ERROR();
+ // 4. Let resultCapability be ? NewPromiseCapability(C).
ScopedObject nextPromise(scope, e->newPromiseObject(constructor, capability));
capability->d()->promise.set(scope.engine, nextPromise);
@@ -811,21 +874,25 @@ ReturnedValue PromisePrototype::method_then(const FunctionObject *f, const Value
Scoped<PromiseReaction> rejectReaction(scope, Heap::PromiseReaction::createRejectReaction(scope.engine, capability, onRejected));
ScopedValue resolution(scope, promise->d()->resolution);
- if (promise->d()->isPending()) {
+ if (promise->d()->isPending()) { // 7. If promise.[[PromiseState]] is "pending"
{
+ // Append fulfillReaction as the last element of the List that is promise.[[PromiseFulfillReactions]].
ScopedArrayObject a(scope, promise->d()->fulfillReactions);
ScopedValue newValue(scope, fulfillReaction->d());
a->push_back(newValue);
}
{
+ // Append rejectReaction as the last element of the List that is promise.[[PromiseRejectReactions]].
ScopedArrayObject a(scope, promise->d()->rejectReactions);
ScopedValue newValue(scope, rejectReaction->d());
a->push_back(newValue);
}
- } else if (promise->d()->isFulfilled()) {
- fulfillReaction->as<QV4::PromiseReaction>()->d()->triggerWithValue(e, resolution);
- } else if (promise->d()->isRejected()) {
+ } else if (promise->d()->isFulfilled()) { // 8. Else if promise.[[PromiseState]] is "fulfilled", then
+ // Perform EnqueueJob("PromiseJobs", PromiseReactionJob, « fulfillReaction, value »).
+ fulfillReaction->as<QV4::PromiseReaction>()->d()->triggerWithValue(e, resolution); // Perform EnqueueJob("PromiseJobs", PromiseReactionJob, « fulfillReaction, value »).
+ } else if (promise->d()->isRejected()) { // 9. Else
+ // Perform EnqueueJob("PromiseJobs", PromiseReactionJob, « rejectReaction, reason »).
rejectReaction->as<QV4::PromiseReaction>()->d()->triggerWithValue(e, resolution);
} else {
Q_ASSERT(false);
@@ -889,7 +956,6 @@ ReturnedValue CapabilitiesExecutorWrapper::virtualCall(const FunctionObject *f,
if (argc >= 2 && !argv[1].isUndefined())
capabilities->reject.set(scope.engine, argv[1]);
- // TODO: return?
return Encode::undefined();
}
@@ -929,27 +995,60 @@ ReturnedValue ResolveElementWrapper::virtualCall(const FunctionObject *f, const
ReturnedValue ResolveWrapper::virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
{
+ // 25.4.1.3.2 (ecmase-262/8.0)
+
Q_UNUSED(thisObject);
Scope scope(f);
const ResolveWrapper *self = static_cast<const ResolveWrapper*>(f);
Scoped<PromiseObject> promise(scope, self->d()->promise);
- if (self->d()->alreadyResolved || !promise->d()->isPending())
+ // 4. If alreadyRseolved.[[Value]] is true, return undefined
+ if (self->d()->alreadyResolved || !promise->d()->isPending()) // Why check for pending?
return Encode::undefined();
- ScopedValue value(scope);
+ // 5. Set alreadyResolved.[[Value]] to true
+ self->d()->alreadyResolved = true;
+
+ ScopedValue resolution(scope);
if (argc == 1) {
- value = argv[0];
+ resolution = argv[0];
} else {
- value = Encode::undefined();
+ resolution = Encode::undefined();
}
- self->d()->alreadyResolved = true;
- promise->d()->setState(Heap::PromiseObject::Fulfilled);
- promise->d()->resolution.set(scope.engine, value);
-
- promise->d()->triggerFullfillReactions(scope.engine);
+ if (!resolution->isObject()) { // 7 If Type(resolution) is not Object
+ // then Return FullFillPromise(promise, resolution)
+ // (FullFillPromise will return undefined, so we share the return with the other path which also returns undefined
+ promise->d()->setState(Heap::PromiseObject::Fulfilled);
+ promise->d()->resolution.set(scope.engine, resolution);
+ promise->d()->triggerFullfillReactions(scope.engine);
+ } else {
+ //PromiseObject *promise = resolution->as<PromiseObject>();
+ auto resolutionObject = resolution->as<Object>();
+ ScopedString thenName(scope, scope.engine->newIdentifier(QStringLiteral("then")));
+
+ // 8. Let then be Get(resolution, then)
+ ScopedFunctionObject thenAction { scope, resolutionObject->get(thenName)};
+ // 9. If then is an abrupt completion, then
+ if (scope.engine->hasException) {
+ // Return RecjectPromise(promise, then.[[Value]]
+ ScopedValue thenValue {scope, scope.engine->catchException()};
+ promise->d()->setState(Heap::PromiseObject::Rejected);
+ promise->d()->resolution.set(scope.engine, thenValue);
+ promise->d()->triggerRejectReactions(scope.engine);
+ } else {
+ // 10. Let thenAction be then.[[Value]]
+ if (!thenAction) { // 11. If IsCallable(thenAction) is false
+ promise->d()->setState(Heap::PromiseObject::Fulfilled);
+ promise->d()->resolution.set(scope.engine, resolution);
+ promise->d()->triggerFullfillReactions(scope.engine);
+ } else {
+ // 12. Perform EnqueueJob("PromiseJobs", PromiseResolveThenableJob, « promise, resolution, thenAction »).
+ scope.engine->getPromiseReactionHandler()->addResolveThenable(scope.engine, promise.getPointer(), resolutionObject, thenAction);
+ }
+ }
+ }
return Encode::undefined();
}
@@ -972,11 +1071,25 @@ ReturnedValue RejectWrapper::virtualCall(const FunctionObject *f, const Value *t
value = Encode::undefined();
}
- self->d()->alreadyResolved = true;
- promise->d()->setState(Heap::PromiseObject::Rejected);
- promise->d()->resolution.set(scope.engine, value);
+ if (!isPromise(value)) {
+ self->d()->alreadyResolved = true;
+ promise->d()->setState(Heap::PromiseObject::Rejected);
+ promise->d()->resolution.set(scope.engine, value);
+
+ promise->d()->triggerRejectReactions(scope.engine);
- promise->d()->triggerRejectReactions(scope.engine);
+ } else {
+ PromiseObject *promise = value->as<PromiseObject>();
+ ScopedString thenName(scope, scope.engine->newIdentifier(QStringLiteral("catch")));
+
+ ScopedFunctionObject then(scope, promise->get(thenName));
+ JSCallData jsCallData(scope, 2);
+ jsCallData->args[0] = *f;
+ jsCallData->args[1] = Encode::undefined();
+ jsCallData->thisObject = value;
+
+ then->call(jsCallData);
+ }
return Encode::undefined();
}
diff --git a/src/qml/jsruntime/qv4promiseobject_p.h b/src/qml/jsruntime/qv4promiseobject_p.h
index bce59b19a7..8a3724e07d 100644
--- a/src/qml/jsruntime/qv4promiseobject_p.h
+++ b/src/qml/jsruntime/qv4promiseobject_p.h
@@ -62,6 +62,7 @@ struct PromiseCapability;
namespace Promise {
struct ReactionEvent;
+struct ResolveThenableEvent;
class ReactionHandler : public QObject
{
@@ -69,13 +70,15 @@ class ReactionHandler : public QObject
public:
ReactionHandler(QObject *parent = nullptr);
- virtual ~ReactionHandler();
+ virtual ~ReactionHandler() override;
void addReaction(ExecutionEngine *e, const Value *reaction, const Value *value);
+ void addResolveThenable(ExecutionEngine *e, const PromiseObject *promise, const Object *thenable, const FunctionObject *then);
protected:
- void customEvent(QEvent *event);
+ void customEvent(QEvent *event) override;
void executeReaction(ReactionEvent *event);
+ void executeResolveThenable(ResolveThenableEvent *event);
};
} // Promise
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index f4cdb45aff..5102fb111c 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -395,9 +395,18 @@ void findCompositeSingletons(const QQmlImportNamespace &set, QList<QQmlImports::
const QQmlDirComponents &components = import->qmlDirComponents;
+ const int importMajorVersion = import->majversion;
+ const int importMinorVersion = import->minversion;
+ auto shouldSkipSingleton = [importMajorVersion, importMinorVersion](int singletonMajorVersion, int singletonMinorVersion) -> bool {
+ return importMajorVersion != -1 &&
+ (singletonMajorVersion > importMajorVersion || (singletonMajorVersion == importMajorVersion && singletonMinorVersion > importMinorVersion));
+ };
+
ConstIterator cend = components.constEnd();
for (ConstIterator cit = components.constBegin(); cit != cend; ++cit) {
if (cit->singleton && excludeBaseUrl(import->url, cit->fileName, baseUrl.toString())) {
+ if (shouldSkipSingleton(cit->majorVersion, cit->minorVersion))
+ continue;
QQmlImports::CompositeSingletonReference ref;
ref.typeName = cit->typeName;
ref.prefix = set.prefix;
@@ -408,7 +417,9 @@ void findCompositeSingletons(const QQmlImportNamespace &set, QList<QQmlImports::
}
if (QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion)) {
- module->walkCompositeSingletons([&resultList, &set](const QQmlType &singleton) {
+ module->walkCompositeSingletons([&resultList, &set, &shouldSkipSingleton](const QQmlType &singleton) {
+ if (shouldSkipSingleton(singleton.majorVersion(), singleton.minorVersion()))
+ return;
QQmlImports::CompositeSingletonReference ref;
ref.typeName = singleton.elementName();
ref.prefix = set.prefix;
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index b435f8ef66..4db0562c0e 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -1570,7 +1570,8 @@ void QQmlXMLHttpRequest::dispatchCallbackNow(Object *thisObj, bool done, bool er
if (scope.engine->hasException) {
QQmlError error = scope.engine->catchExceptionAsQmlError();
- QQmlEnginePrivate::warning(QQmlEnginePrivate::get(scope.engine->qmlEngine()), error);
+ QQmlEnginePrivate *qmlEnginePrivate = scope.engine->qmlEngine() ? QQmlEnginePrivate::get(scope.engine->qmlEngine()) : nullptr;
+ QQmlEnginePrivate::warning(qmlEnginePrivate, error);
}
};
@@ -1761,8 +1762,13 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(const FunctionObject *b, const
// Argument 1 - URL
QUrl url = QUrl(argv[1].toQStringNoThrow());
- if (url.isRelative())
- url = scope.engine->callingQmlContext()->resolvedUrl(url);
+ if (url.isRelative()) {
+ QQmlContextData *qmlContextData = scope.engine->callingQmlContext();
+ if (qmlContextData)
+ url = qmlContextData->resolvedUrl(url);
+ else
+ url = scope.engine->resolvedUrl(url.url());
+ }
bool async = true;
// Argument 2 - async (optional)
diff --git a/src/quick/doc/images/sg-renderloop-singlethreaded.jpg b/src/quick/doc/images/sg-renderloop-singlethreaded.jpg
deleted file mode 100644
index c6d1577138..0000000000
--- a/src/quick/doc/images/sg-renderloop-singlethreaded.jpg
+++ /dev/null
Binary files differ
diff --git a/src/quick/doc/images/sg-renderloop-singlethreaded.png b/src/quick/doc/images/sg-renderloop-singlethreaded.png
new file mode 100644
index 0000000000..ad5ce62690
--- /dev/null
+++ b/src/quick/doc/images/sg-renderloop-singlethreaded.png
Binary files differ
diff --git a/src/quick/doc/images/sg-renderloop-threaded.jpg b/src/quick/doc/images/sg-renderloop-threaded.jpg
deleted file mode 100644
index 2f7d97591b..0000000000
--- a/src/quick/doc/images/sg-renderloop-threaded.jpg
+++ /dev/null
Binary files differ
diff --git a/src/quick/doc/images/sg-renderloop-threaded.png b/src/quick/doc/images/sg-renderloop-threaded.png
new file mode 100644
index 0000000000..1b1d6c7b11
--- /dev/null
+++ b/src/quick/doc/images/sg-renderloop-threaded.png
Binary files differ
diff --git a/src/quick/doc/images/sg-renderloop-threaded.xml b/src/quick/doc/images/sg-renderloop-threaded.xml
new file mode 100644
index 0000000000..857720b93a
--- /dev/null
+++ b/src/quick/doc/images/sg-renderloop-threaded.xml
@@ -0,0 +1,2 @@
+<mxfile modified="2019-07-16T06:49:28.503Z" host="www.draw.io" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1 Safari/605.1.15" etag="GcefJOKlDSi76bXNeTL1" version="10.9.7" type="device"><diagram id="HMeFProKuhY0WpDPD-Gk" name="Page-1">7Vptc5s4EP41nrn7kBsMhtofbcfNddq0ddxO7/qlI8MCuoDECeGX/vouQhgT2alvxj4mvptJHHYlgXiefdM6PWeabu4EyeJ7HkDSs61g03Nue7bdt0Y2/ik120rjWcNKEQka6EmNYkG/Q71SawsaQN6aKDlPJM3aSp8zBr5s6YgQfN2eFvKk/dSMRGAoFj5JTO0XGshYa/veqBn4HWgU60cP7VfVQErqyfpN8pgEfL2ncmY9Zyo4l9VVuplCUoJX41Kte31kdLcxAUyesuDtdDWYhvej8Gb91vs6mQfx5MONvksut/ULQ4Dvr0UuZMwjzkgya7QTwQsWQHnXPkrNnHecZ1r5F0i51WSSQnJUxTJN9ChuWGz/QMGqhT9L4Te3Fm83+4O3Wy2FnEl9076HcrX3csNHIanfjxfC17Pu6XIczInDvn5abLeWO2ffPtc4SCIikM/Mc3fEocUDTwH3h+sEJETSVXsfRJtetJvXsIMXmqDDZD23yRVJCv2k+byg/uMbCWnPGeNPkQVEwi+/Gqy2OVvHVMIiIwqSNTpum5+QJsmUJ1yotU5AYBj6qM+l4I+wN+L5Q1iGOyZWICRsnufCxK5e4Go/0YGiX/vNunE7e6R18Z7H1evODrd9ItwfeULz+DpAH3UNumOAfvf5Tbkox49lwv1HBPScQIdDH/yDQC+H7sC1LgM05sHTgN65wdmRHhhIj4MVYYiabY0ZxfxFOStRn63Kl7Stj4L7kOeURT0bH+kluMXJUuBVVF4RFqhIix+cXYEvDKzOKXINihaYoaRiwCL4y2BdFjWCpGAS8iEDdvcOx6eYN2Ejay9KSVBy7BdCQfPymHJttx21Bm7XqcIyYPw366idUNVR9j8opOwmwJ2lkPJOLKScLgspz/CrCUSUle+3ZX4sOKPfVfgznUqlIJyostLL95xR157zyqACUlqGqqrW+kKZOjSV1dYSQi5gsWMIw+C5iy4XhsHgEAlDe+l43mVIsDsPX0ODhCOVLqFMvscz/nXg3rnx2/b/aaNCYnRi2hh0mTZGhpvMqpr3Z0mjYBdLG514jtN5xKrbg6fnjQdAkMUFckYnidvpPHb1zW7UwgdWnixUK7g+bQiF+5kP7d2APuje7M2e1FGzJ6EEcV1WP+je6s3+VHXMrs/YCvp8TbJJEYYg8qvA3e3e8M1u1VHDV+2QBVKQQXAd8Hdv9mYn6nXVdKqCvM/TLAFZylUbkKvDtC8AXmIr8CkBXvf2b7YsVCnZVJp7CHt/F+WXiqpev8lVwT7GCX0v2yh86vG6PB1nWUJ9Xbta93jI+xQLIGbKriLcPj1tGhhn8IQzrSIJjRiKWCFgVkJFyQ8+MxnrgZQGgTreHLKHxmIOfQ2oZL3J/hnYf9oIdk4k37sY+WaT5GH2/nb2cCb+n9Zt/2n2jUr7cuyj2Hz9r8b2/onCmf0A</diagram><diagram id="ARaiocFhs8Yj9Ub61lwa" name="Page-2">5Zhbb9owFMc/TaTtYVIuEOARKPSidmubdp36ZuKTxMOxM8c00E8/O3EKNEyj09ZImQQi+R9fwvn5nGPH8qbp+lSgLLniGKjl2nhteSeW6zr2yFU/WtlUim8PKyEWBJtGWyEgz1D3NOqKYMj3GkrOqSTZvhhyxiCUexoSghf7zSJO92fNUAwNIQgRbaoPBMvEqI4/2hrOgMSJmXroDipDiurG5p/kCcK82JG8meVNBeeyukrXU6DaebVfZrd3PwbzydlDf3kT4Mfomkzpp2qw+Vu6vPwFAUz+8dAXrP/1+7q3XDznxWKTedgfxaaL/YToyvjr5mZFwuW5hNTyxuqzyjCSYDwgN7VbBV8xDHpox/ImRUIkBBkKtbVQC0lpiUypMUeE0imnXJR9PYxgGIVKz6XgS9ix+OEQFpGymMcCIWH9iuNvnOC8kFFLGngKUmxUPzNK3+1X45jV7NRwi+3acEdGS3aWRd9oyCzH+GXorcvVhfH6Gwg4RxK45pTkyYePnSUxaJuE2yBxen9uuT5VE08WQl3F+mqcZZSESBLOVOsrRPTPXSIA4QYb5TO5D2Df0YwzeEXFSIiSmKnbUPkYlD7RBNS0dGwMKcFYT3OQ+HZN2Hp4zqRJzI5f35uHdN6Lr3ckXv8v4E2WF9i5n82Dk/Pb4Fs2S9eXjwdSXSCR8imL9Wzqy6DQBUagFJrUv2TATi+Vfaqcp6mq2fKySmDQ1WslSm91NDjd90yTB+k10ySkRFOosuUDYWVt1vlyAREXEGxYmAjOyLMi3N206b5n2jxIppk2f1HAVKaUn9X+srswvNbDxHtrmNyCcrzodIh4rYdIr1l6VF3XdaM8dNW1RJQsoLmN6AiIXuvh0T8+PFCk9l3/QXT0Wo8OvwGl2mzVO60SR16gbLKKIhB5d1n0Ww+QwfEBUm6UA4UlA9xhJK2Hx7CBZF4dUaqiEfI0o6Df0NiIqdJhl8fSPBQArKtQ/NbjZNSAMsZPiIUaw5iRtH49MHsqT4X2teAh5Hl52Jw2T5cVuZwbfB2l9g9DSd1uX8SWtp3X2d7sJw==</diagram></mxfile>
+
diff --git a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
index 9383c78a42..ee6c501c71 100644
--- a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
+++ b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
@@ -210,7 +210,7 @@ and when interaction with the scene graph can happen.
The following is a simple outline of how a frame gets
composed with the threaded render loop.
-\image sg-renderloop-threaded.jpg
+\image sg-renderloop-threaded.png
\list 1
@@ -301,7 +301,7 @@ will make the code non-portable.
The following is a simplified illustration of the frame rendering
sequence in the non-threaded renderer.
-\image sg-renderloop-singlethreaded.jpg
+\image sg-renderloop-singlethreaded.png
\section2 Custom control over rendering with QQuickRenderControl
diff --git a/src/quick/handlers/qquickhandlerpoint.cpp b/src/quick/handlers/qquickhandlerpoint.cpp
index de21537f27..f3d92cf200 100644
--- a/src/quick/handlers/qquickhandlerpoint.cpp
+++ b/src/quick/handlers/qquickhandlerpoint.cpp
@@ -51,13 +51,14 @@ Q_DECLARE_LOGGING_CATEGORY(DBG_TOUCH_TARGET)
A QML representation of a QQuickEventPoint.
- It's possible to make bindings to properties of a \l SinglePointHandler's
- current point. For example:
+ It's possible to make bindings to properties of a handler's current
+ \l {SinglePointHandler::point}{point} or
+ \l {MultiPointHandler::centroid}{centroid}. For example:
\snippet pointerHandlers/dragHandlerNullTarget.qml 0
The point is kept up-to-date when the DragHandler is actively responding to
- an EventPoint; but when the point is released, or the current point is
+ an EventPoint; but after the point is released, or when the current point is
being handled by a different handler, \c position.x and \c position.y are 0.
\note This is practically identical to QtQuick::EventPoint; however an
@@ -68,7 +69,7 @@ Q_DECLARE_LOGGING_CATEGORY(DBG_TOUCH_TARGET)
handler is handling. HandlerPoint is a Q_GADGET that the handler owns.
This allows you to make lifetime bindings to its properties.
- \sa SinglePointHandler::point
+ \sa SinglePointHandler::point, MultiPointHandler::centroid
*/
QQuickHandlerPoint::QQuickHandlerPoint()
@@ -106,12 +107,6 @@ void QQuickHandlerPoint::reset(const QQuickEventPoint *point)
m_scenePressPosition = point->scenePosition();
m_pressedButtons = event->buttons();
break;
- case QQuickEventPoint::Released:
- if (event->buttons() == Qt::NoButton) {
- reset();
- return;
- }
- break;
default:
break;
}
diff --git a/src/quick/handlers/qquickhoverhandler.cpp b/src/quick/handlers/qquickhoverhandler.cpp
index 61955cad03..d7566f0cd8 100644
--- a/src/quick/handlers/qquickhoverhandler.cpp
+++ b/src/quick/handlers/qquickhoverhandler.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qquickhoverhandler_p.h"
+#include <private/qquicksinglepointhandler_p_p.h>
QT_BEGIN_NAMESPACE
@@ -59,6 +60,8 @@ Q_LOGGING_CATEGORY(lcHoverHandler, "qt.quick.handler.hover")
QQuickHoverHandler::QQuickHoverHandler(QQuickItem *parent)
: QQuickSinglePointHandler(parent)
{
+ // Tell QQuickPointerDeviceHandler::wantsPointerEvent() to ignore button state
+ d_func()->acceptedButtons = Qt::NoButton;
// Rule out the touchscreen for now (can be overridden in QML in case a hover-detecting touchscreen exists)
setAcceptedDevices(static_cast<QQuickPointerDevice::DeviceType>(
static_cast<int>(QQuickPointerDevice::AllDevices) ^ static_cast<int>(QQuickPointerDevice::TouchScreen)));
diff --git a/src/quick/handlers/qquickpointerdevicehandler.cpp b/src/quick/handlers/qquickpointerdevicehandler.cpp
index 096fad2071..449d726b78 100644
--- a/src/quick/handlers/qquickpointerdevicehandler.cpp
+++ b/src/quick/handlers/qquickpointerdevicehandler.cpp
@@ -256,6 +256,11 @@ bool QQuickPointerDeviceHandler::wantsPointerEvent(QQuickPointerEvent *event)
return false;
if (d->acceptedModifiers != Qt::KeyboardModifierMask && event->modifiers() != d->acceptedModifiers)
return false;
+ // HoverHandler sets acceptedButtons to Qt::NoButton to indicate that button state is irrelevant.
+ if (event->device()->pointerType() != QQuickPointerDevice::Finger && acceptedButtons() != Qt::NoButton &&
+ (event->buttons() & acceptedButtons()) == 0 && (event->button() & acceptedButtons()) == 0
+ && !event->asPointerScrollEvent())
+ return false;
return true;
}
diff --git a/src/quick/handlers/qquicksinglepointhandler.cpp b/src/quick/handlers/qquicksinglepointhandler.cpp
index c0fa39fad3..15fe0cc89e 100644
--- a/src/quick/handlers/qquicksinglepointhandler.cpp
+++ b/src/quick/handlers/qquicksinglepointhandler.cpp
@@ -74,9 +74,6 @@ bool QQuickSinglePointHandler::wantsPointerEvent(QQuickPointerEvent *event)
Q_D(QQuickSinglePointHandler);
if (!QQuickPointerDeviceHandler::wantsPointerEvent(event))
return false;
- if (event->device()->pointerType() != QQuickPointerDevice::Finger &&
- (event->buttons() & acceptedButtons()) == 0 && (event->button() & acceptedButtons()) == 0)
- return false;
if (d->pointInfo.id()) {
// We already know which one we want, so check whether it's there.
diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp
index 40a4813527..255e47d73a 100644
--- a/src/quick/handlers/qquicktaphandler.cpp
+++ b/src/quick/handlers/qquicktaphandler.cpp
@@ -392,9 +392,6 @@ void QQuickTapHandler::updateTimeHeld()
from the release event about the point that was tapped:
\snippet pointerHandlers/tapHandlerOnTapped.qml 0
-
- \note At the time this signal is emitted, \l point has been reset
- (all coordinates are \c 0).
*/
/*!
@@ -406,9 +403,6 @@ void QQuickTapHandler::updateTimeHeld()
it can be tapped again; but if the time until the next tap is less,
\l tapCount will increase. The \c eventPoint signal parameter contains
information from the release event about the point that was tapped.
-
- \note At the time this signal is emitted, \l point has been reset
- (all coordinates are \c 0).
*/
/*!
@@ -422,9 +416,6 @@ void QQuickTapHandler::updateTimeHeld()
\l singleTapped, \l tapped, and \l tapCountChanged. The \c eventPoint
signal parameter contains information from the release event about the
point that was tapped.
-
- \note At the time this signal is emitted, \l point has been reset
- (all coordinates are \c 0).
*/
/*!
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index 28b217b7b3..8303c3fed1 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -913,10 +913,14 @@ void QQuickEventPoint::setGrabberPointerHandler(QQuickPointerHandler *grabber, b
passiveGrabber->onGrabChanged(grabber, OverrideGrabPassive, this);
}
}
- if (oldGrabberHandler)
+ if (oldGrabberHandler) {
oldGrabberHandler->onGrabChanged(oldGrabberHandler, (grabber ? CancelGrabExclusive : UngrabExclusive), this);
- else if (oldGrabberItem && pointerEvent()->asPointerTouchEvent())
- oldGrabberItem->touchUngrabEvent();
+ } else if (oldGrabberItem) {
+ if (pointerEvent()->asPointerTouchEvent())
+ oldGrabberItem->touchUngrabEvent();
+ else if (pointerEvent()->asPointerMouseEvent())
+ oldGrabberItem->mouseUngrabEvent();
+ }
// touchUngrabEvent() can result in the grabber being set to null (MPTA does that, for example).
// So set it again to ensure that final state is what we want.
m_exclusiveGrabber = QPointer<QObject>(grabber);
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 95f1229b92..bbfbf6244c 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -1852,6 +1852,9 @@ void QQuickItemViewPrivate::layout()
forceLayout = false;
if (transitioner && transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) {
+ // Give the view one more chance to refill itself,
+ // in case its size is changed such that more delegates become visible after component completed
+ refill();
for (FxViewItem *item : qAsConst(visibleItems)) {
if (!item->transitionScheduledOrRunning())
item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::PopulateTransition, true);
diff --git a/src/quick/items/qquickshadereffectmesh_p.h b/src/quick/items/qquickshadereffectmesh_p.h
index 62a9798e40..79e05a5f9f 100644
--- a/src/quick/items/qquickshadereffectmesh_p.h
+++ b/src/quick/items/qquickshadereffectmesh_p.h
@@ -66,8 +66,8 @@ QT_REQUIRE_CONFIG(quick_shadereffect);
QT_BEGIN_NAMESPACE
-const char *qtPositionAttributeName();
-const char *qtTexCoordAttributeName();
+Q_QUICK_PRIVATE_EXPORT const char *qtPositionAttributeName();
+Q_QUICK_PRIVATE_EXPORT const char *qtTexCoordAttributeName();
class QSGGeometry;
class QRectF;
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index c51cfc8ac1..b55c578b12 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -3804,6 +3804,12 @@ bool QQuickWindow::isSceneGraphInitialized() const
This signal is emitted when the window receives the event \a close from
the windowing system.
+
+ On \macOs, Qt will create a menu item \c Quit if there is no menu item
+ whose text is "quit" or "exit". This menu item calls the \c QCoreApplication::quit
+ signal, not the \c QQuickWindow::closing() signal.
+
+ \sa {QMenuBar as a Global Menu Bar}
*/
/*!
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode.cpp b/src/quick/scenegraph/qsgdefaultglyphnode.cpp
index ba286b8a36..5bd5cc4891 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode.cpp
@@ -76,7 +76,7 @@ void QSGDefaultGlyphNode::update()
QMargins margins(0, 0, 0, 0);
if (m_style == QQuickText::Normal) {
- m_material = new QSGTextMaskMaterial(m_context, font);
+ m_material = new QSGTextMaskMaterial(m_context, QVector4D(m_color.redF(), m_color.greenF(), m_color.blueF(), m_color.alphaF()), font);
} else if (m_style == QQuickText::Outline) {
QSGOutlinedTextMaterial *material = new QSGOutlinedTextMaterial(m_context, font);
material->setStyleColor(m_styleColor);
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
index 8ce469b39b..5a66f1dfef 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -687,11 +687,12 @@ public:
// ***** common material stuff
-QSGTextMaskMaterial::QSGTextMaskMaterial(QSGRenderContext *rc, const QRawFont &font, QFontEngine::GlyphFormat glyphFormat)
+QSGTextMaskMaterial::QSGTextMaskMaterial(QSGRenderContext *rc, const QVector4D &color, const QRawFont &font, QFontEngine::GlyphFormat glyphFormat)
: m_rc(qobject_cast<QSGDefaultRenderContext *>(rc))
, m_texture(nullptr)
, m_glyphCache(nullptr)
, m_font(font)
+ , m_color(color)
{
init(glyphFormat);
}
@@ -701,6 +702,19 @@ QSGTextMaskMaterial::~QSGTextMaskMaterial()
delete m_texture;
}
+void QSGTextMaskMaterial::setColor(const QVector4D &color)
+{
+ if (m_color == color)
+ return;
+
+ m_color = color;
+
+ // If it is an RGB cache, then the pen color is actually part of the cache key
+ // so it has to be updated
+ if (m_glyphCache != nullptr && m_glyphCache->glyphFormat() == QFontEngine::Format_ARGB)
+ updateCache(QFontEngine::Format_ARGB);
+}
+
void QSGTextMaskMaterial::init(QFontEngine::GlyphFormat glyphFormat)
{
Q_ASSERT(m_font.isValid());
@@ -711,6 +725,11 @@ void QSGTextMaskMaterial::init(QFontEngine::GlyphFormat glyphFormat)
Q_ASSERT(m_rc);
m_rhi = m_rc->rhi();
+ updateCache(glyphFormat);
+}
+
+void QSGTextMaskMaterial::updateCache(QFontEngine::GlyphFormat glyphFormat)
+{
// The following piece of code will read/write to the font engine's caches,
// potentially from different threads. However, this is safe because this
// code is only called from QQuickItem::updatePaintNode() which is called
@@ -745,13 +764,13 @@ void QSGTextMaskMaterial::init(QFontEngine::GlyphFormat glyphFormat)
if (!fontEngine->supportsTransformation(glyphCacheTransform))
glyphCacheTransform = QTransform();
- m_glyphCache = fontEngine->glyphCache(cacheKey, glyphFormat, glyphCacheTransform);
-
+ //QColor color = glyphFormat == QFontEngine::Format_ARGB ? QColor::fromRgbF(m_color.x(), m_color.y(), m_color.z(), m_color.w()) : QColor();
+ m_glyphCache = fontEngine->glyphCache(cacheKey, glyphFormat, glyphCacheTransform); // ### restore color arg when merges are done
if (!m_glyphCache || int(m_glyphCache->glyphFormat()) != glyphFormat) {
if (m_rhi)
- m_glyphCache = new QSGRhiTextureGlyphCache(m_rhi, glyphFormat, glyphCacheTransform);
+ m_glyphCache = new QSGRhiTextureGlyphCache(m_rhi, glyphFormat, glyphCacheTransform); // ### color
else
- m_glyphCache = new QOpenGLTextureGlyphCache(glyphFormat, glyphCacheTransform);
+ m_glyphCache = new QOpenGLTextureGlyphCache(glyphFormat, glyphCacheTransform); // ### restore color arg when merges are done
fontEngine->setGlyphCache(cacheKey, m_glyphCache.data());
m_rc->registerFontengineForCleanup(fontEngine);
@@ -963,7 +982,7 @@ bool QSGTextMaskMaterial::ensureUpToDate()
QSGStyledTextMaterial::QSGStyledTextMaterial(QSGRenderContext *rc, const QRawFont &font)
- : QSGTextMaskMaterial(rc, font, QFontEngine::Format_A8)
+ : QSGTextMaskMaterial(rc, QVector4D(), font, QFontEngine::Format_A8)
{
}
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p_p.h b/src/quick/scenegraph/qsgdefaultglyphnode_p_p.h
index cd1b331278..7d2635794d 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p_p.h
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p_p.h
@@ -72,15 +72,15 @@ class QSGDefaultRenderContext;
class QSGTextMaskMaterial: public QSGMaterial
{
public:
- QSGTextMaskMaterial(QSGRenderContext *rc, const QRawFont &font, QFontEngine::GlyphFormat glyphFormat = QFontEngine::Format_None);
+ QSGTextMaskMaterial(QSGRenderContext *rc, const QVector4D &color, const QRawFont &font, QFontEngine::GlyphFormat glyphFormat = QFontEngine::Format_None);
virtual ~QSGTextMaskMaterial();
QSGMaterialType *type() const override;
QSGMaterialShader *createShader() const override;
int compare(const QSGMaterial *other) const override;
- void setColor(const QColor &c) { m_color = QVector4D(c.redF(), c.greenF(), c.blueF(), c.alphaF()); }
- void setColor(const QVector4D &color) { m_color = color; }
+ void setColor(const QColor &c) { setColor(QVector4D(c.redF(), c.greenF(), c.blueF(), c.alphaF())); }
+ void setColor(const QVector4D &color);
const QVector4D &color() const { return m_color; }
QSGTexture *texture() const { return m_texture; }
@@ -98,6 +98,7 @@ public:
private:
void init(QFontEngine::GlyphFormat glyphFormat);
+ void updateCache(QFontEngine::GlyphFormat glyphFormat);
QSGDefaultRenderContext *m_rc;
QSGPlainTexture *m_texture;
diff --git a/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp b/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp
index 33efcb4da4..9fe2de5368 100644
--- a/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp
+++ b/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp
@@ -597,7 +597,7 @@ void SingleTest::run()
void SingleTest::runExternalTest()
{
- auto runTest = [=] (const char *header, TestCase::Result *result) {
+ auto runTest = [this] (const char *header, TestCase::Result *result) {
QTemporaryFile tempFile;
tempFile.open();
tempFile.write(header);
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index e08a1cc37e..0ccb8210bc 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -249,6 +249,8 @@ private slots:
void interrupt_data();
void interrupt();
+ void triggerBackwardJumpWithDestructuring();
+
public:
Q_INVOKABLE QJSValue throwingCppMethod1();
Q_INVOKABLE void throwingCppMethod2();
@@ -4938,6 +4940,19 @@ void tst_QJSEngine::interrupt()
#endif
}
+void tst_QJSEngine::triggerBackwardJumpWithDestructuring()
+{
+ QJSEngine engine;
+ auto value = engine.evaluate(
+ "function makeArray(n) { return [...Array(n).keys()]; }\n"
+ "for (let i=0;i<100;++i) {\n"
+ " let arr = makeArray(20)\n"
+ " arr.sort( (a, b) => b - a )\n"
+ "}"
+ );
+ QVERIFY(!value.isError());
+}
+
QTEST_MAIN(tst_QJSEngine)
#include "tst_qjsengine.moc"
diff --git a/tests/auto/qml/qqmlimport/data/QTBUG-77102/imports/MyPlugin/MyComponent_0_9.qml b/tests/auto/qml/qqmlimport/data/QTBUG-77102/imports/MyPlugin/MyComponent_0_9.qml
new file mode 100644
index 0000000000..a63e2d121c
--- /dev/null
+++ b/tests/auto/qml/qqmlimport/data/QTBUG-77102/imports/MyPlugin/MyComponent_0_9.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 50
+ height: 50
+
+ color: "yellow"
+
+ Text {
+ anchors.centerIn: parent
+ text: "0.9"
+
+ }
+}
diff --git a/tests/auto/qml/qqmlimport/data/QTBUG-77102/imports/MyPlugin/MyComponent_1_0.qml b/tests/auto/qml/qqmlimport/data/QTBUG-77102/imports/MyPlugin/MyComponent_1_0.qml
new file mode 100644
index 0000000000..d9cff582bb
--- /dev/null
+++ b/tests/auto/qml/qqmlimport/data/QTBUG-77102/imports/MyPlugin/MyComponent_1_0.qml
@@ -0,0 +1,15 @@
+
+import QtQuick 2.0
+
+Rectangle {
+ width: 50
+ height: 50
+
+ color: "orange"
+
+ Text {
+ anchors.centerIn: parent
+ text: "1.0"
+
+ }
+}
diff --git a/tests/auto/qml/qqmlimport/data/QTBUG-77102/imports/MyPlugin/MySettings_1_0.qml b/tests/auto/qml/qqmlimport/data/QTBUG-77102/imports/MyPlugin/MySettings_1_0.qml
new file mode 100644
index 0000000000..63ad6ba1a5
--- /dev/null
+++ b/tests/auto/qml/qqmlimport/data/QTBUG-77102/imports/MyPlugin/MySettings_1_0.qml
@@ -0,0 +1,7 @@
+pragma Singleton
+
+import QtQuick 2.0
+
+Item {
+ property int baseWidth: 50
+}
diff --git a/tests/auto/qml/qqmlimport/data/QTBUG-77102/imports/MyPlugin/qmldir b/tests/auto/qml/qqmlimport/data/QTBUG-77102/imports/MyPlugin/qmldir
new file mode 100644
index 0000000000..57b8c55f81
--- /dev/null
+++ b/tests/auto/qml/qqmlimport/data/QTBUG-77102/imports/MyPlugin/qmldir
@@ -0,0 +1,6 @@
+module MyPlugin
+
+MyComponent 0.9 MyComponent_0_9.qml
+
+MyComponent 1.0 MyComponent_1_0.qml
+singleton MySettings 1.0 MySettings_1_0.qml
diff --git a/tests/auto/qml/qqmlimport/data/QTBUG-77102/main.0.9.fail.qml b/tests/auto/qml/qqmlimport/data/QTBUG-77102/main.0.9.fail.qml
new file mode 100644
index 0000000000..0fbcec607a
--- /dev/null
+++ b/tests/auto/qml/qqmlimport/data/QTBUG-77102/main.0.9.fail.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.12
+import MyPlugin 0.9
+
+Item {
+ width: MySettings.baseWidth
+ height: 100
+
+ MyComponent {
+ anchors.centerIn: parent
+ }
+}
diff --git a/tests/auto/qml/qqmlimport/data/QTBUG-77102/main.0.9.qml b/tests/auto/qml/qqmlimport/data/QTBUG-77102/main.0.9.qml
new file mode 100644
index 0000000000..53fc25699c
--- /dev/null
+++ b/tests/auto/qml/qqmlimport/data/QTBUG-77102/main.0.9.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.12
+import MyPlugin 0.9
+
+Item {
+ width: 100
+ height: 100
+
+ MyComponent {
+ anchors.centerIn: parent
+ }
+}
diff --git a/tests/auto/qml/qqmlimport/data/QTBUG-77102/main.1.0.qml b/tests/auto/qml/qqmlimport/data/QTBUG-77102/main.1.0.qml
new file mode 100644
index 0000000000..1f6244068b
--- /dev/null
+++ b/tests/auto/qml/qqmlimport/data/QTBUG-77102/main.1.0.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.12
+import MyPlugin 1.0
+
+Item {
+ width: MySettings.baseWidth
+ height: 100
+
+ MyComponent {
+ anchors.centerIn: parent
+ }
+}
diff --git a/tests/auto/qml/qqmlimport/data/QTBUG-77102/main.nonumber.qml b/tests/auto/qml/qqmlimport/data/QTBUG-77102/main.nonumber.qml
new file mode 100644
index 0000000000..dea00c0163
--- /dev/null
+++ b/tests/auto/qml/qqmlimport/data/QTBUG-77102/main.nonumber.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.12
+import "imports/MyPlugin"
+
+Item {
+ width: MySettings.baseWidth
+ height: 100
+
+ MyComponent {
+ anchors.centerIn: parent
+ }
+}
diff --git a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp
index a3cb68fdcb..a9657eba1d 100644
--- a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp
+++ b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp
@@ -45,6 +45,7 @@ private slots:
void completeQmldirPaths_data();
void completeQmldirPaths();
void interceptQmldir();
+ void singletonVersionResolution();
void cleanup();
};
@@ -212,6 +213,50 @@ void tst_QQmlImport::interceptQmldir()
QVERIFY(!obj.isNull());
}
+// QTBUG-77102
+void tst_QQmlImport::singletonVersionResolution()
+{
+ QQmlEngine engine;
+ engine.addImportPath(testFile("QTBUG-77102/imports"));
+ {
+ // Singleton with higher version is simply ignored when importing lower version of plugin
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("QTBUG-77102/main.0.9.qml"));
+ QVERIFY(component.isReady());
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ }
+ {
+ // but the singleton is not accessible
+ QQmlComponent component(&engine);
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, QRegularExpression {".*ReferenceError: MySettings is not defined$"} );
+ component.loadUrl(testFileUrl("QTBUG-77102/main.0.9.fail.qml"));
+ QVERIFY(component.isReady());
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ }
+ {
+ // unless a version which is high enough is imported
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("QTBUG-77102/main.1.0.qml"));
+ QVERIFY(component.isReady());
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ auto item = qobject_cast<QQuickItem*>(obj.get());
+ QCOMPARE(item->width(), 50);
+ }
+ {
+ // or when there is no number because we are importing from a path
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("QTBUG-77102/main.nonumber.qml"));
+ QVERIFY(component.isReady());
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ auto item = qobject_cast<QQuickItem*>(obj.get());
+ QCOMPARE(item->width(), 50);
+ }
+}
+
QTEST_MAIN(tst_QQmlImport)
diff --git a/tests/auto/qml/qqmlpromise/data/promisechain.qml b/tests/auto/qml/qqmlpromise/data/promisechain.qml
new file mode 100644
index 0000000000..fa1809aef0
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promisechain.qml
@@ -0,0 +1,24 @@
+import QtQml 2.0
+
+QtObject {
+ property int x: 0
+ id: root;
+ Component.onCompleted: {
+ new Promise((res) => {
+ res(1)
+ })
+ .then((data) => {
+ console.debug(data)
+ return new Promise((res) => {res(2)});
+ })
+ .then((data) => {
+ console.debug(data)
+ return new Promise((res) => {res(3)});
+ })
+ .then((data) => {
+ console.debug(data);
+ root.x = 42;
+ });
+ }
+
+}
diff --git a/tests/auto/qml/qqmlpromise/tst_qqmlpromise.cpp b/tests/auto/qml/qqmlpromise/tst_qqmlpromise.cpp
index 0f4bb5cdcc..41850d0263 100644
--- a/tests/auto/qml/qqmlpromise/tst_qqmlpromise.cpp
+++ b/tests/auto/qml/qqmlpromise/tst_qqmlpromise.cpp
@@ -82,6 +82,7 @@ private slots:
void then_fulfilled_non_callable();
void then_reject_non_callable();
void then_resolve_multiple_then();
+ void promiseChain();
private:
void execute_test(QString testName);
@@ -270,6 +271,20 @@ void tst_qqmlpromise::execute_test(QString testName)
QTRY_COMPARE(object->property("wasTestSuccessful").toBool(), true);
}
+void tst_qqmlpromise::promiseChain()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("promisechain.qml"));
+ QVERIFY(component.isReady());
+ QTest::ignoreMessage(QtDebugMsg, "1");
+ QTest::ignoreMessage(QtDebugMsg, "2");
+ QTest::ignoreMessage(QtDebugMsg, "3");
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY(root);
+ QTRY_VERIFY(root->property("x") == 42);
+
+}
+
QTEST_MAIN(tst_qqmlpromise)
diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/dragParentOfMPTA.qml b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/dragParentOfMPTA.qml
new file mode 100644
index 0000000000..dc7e5f6411
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/dragParentOfMPTA.qml
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+
+Item {
+ width: 640
+ height: 480
+ property alias touchpointPressed: tp1.pressed
+
+ Rectangle {
+ color: tp1.pressed ? "lightsteelblue" : drag.active ? "tomato" : "wheat"
+ width: 180
+ height: 180
+
+ DragHandler { id: drag }
+
+ MultiPointTouchArea {
+ anchors.fill: parent
+ touchPoints: [
+ TouchPoint { id: tp1 }
+ ]
+ }
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp
index 58bc3d40b5..35fed99e8b 100644
--- a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp
+++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp
@@ -56,6 +56,7 @@ private slots:
void touchDrag();
void touchesThenPinch();
void unloadHandlerWithPassiveGrab();
+ void dragHandlerInParentStealingGrabFromItem();
private:
void createView(QScopedPointer<QQuickView> &window, const char *fileName);
@@ -300,6 +301,48 @@ void tst_MptaInterop::unloadHandlerWithPassiveGrab()
QTest::mouseRelease(window, Qt::LeftButton, 0, point); // QTBUG-73819: don't crash
}
+void tst_MptaInterop::dragHandlerInParentStealingGrabFromItem() // QTBUG-75025
+{
+ const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
+ QScopedPointer<QQuickView> windowPtr;
+ createView(windowPtr, "dragParentOfMPTA.qml");
+ QQuickView * window = windowPtr.data();
+ auto pointerEvent = QQuickWindowPrivate::get(window)->pointerEventInstance(QQuickPointerDevice::genericMouseDevice());
+
+ QPointer<QQuickPointerHandler> handler = window->rootObject()->findChild<QQuickPointerHandler*>();
+ QVERIFY(handler);
+ QQuickMultiPointTouchArea *mpta = window->rootObject()->findChild<QQuickMultiPointTouchArea*>();
+ QVERIFY(mpta);
+
+ // In QTBUG-75025 there is a QQ Controls Button; the MPTA here stands in for that,
+ // simply as an Item that grabs the mouse. The bug has nothing to do with MPTA specifically.
+
+ QPoint point(20, 20);
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, point);
+ QCOMPARE(window->mouseGrabberItem(), mpta);
+ QCOMPARE(window->rootObject()->property("touchpointPressed").toBool(), true);
+
+ // Start dragging
+ // DragHandler keeps monitoring, due to its passive grab,
+ // and eventually steals the exclusive grab from MPTA
+ int dragStoleGrab = 0;
+ for (int i = 0; i < 4; ++i) {
+ point += QPoint(dragThreshold / 2, 0);
+ QTest::mouseMove(window, point);
+ if (!dragStoleGrab && pointerEvent->point(0)->exclusiveGrabber() == handler)
+ dragStoleGrab = i;
+ }
+ if (dragStoleGrab)
+ qCDebug(lcPointerTests, "DragHandler stole the grab after %d events", dragStoleGrab);
+ QVERIFY(dragStoleGrab > 1);
+ QCOMPARE(handler->active(), true);
+ QCOMPARE(window->rootObject()->property("touchpointPressed").toBool(), false);
+
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, point);
+ QCOMPARE(handler->active(), false);
+ QCOMPARE(window->rootObject()->property("touchpointPressed").toBool(), false);
+}
+
QTEST_MAIN(tst_MptaInterop)
#include "tst_multipointtoucharea_interop.moc"
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
index 7636bb38f1..66314f88a2 100644
--- a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
@@ -54,6 +54,7 @@ private slots:
void defaultPropertyValues();
void touchDrag();
+ void mouseDrag_data();
void mouseDrag();
void dragFromMargin();
void snapMode_data();
@@ -195,8 +196,22 @@ void tst_DragHandler::touchDrag()
QCOMPARE(centroidChangedSpy.count(), 5);
}
+void tst_DragHandler::mouseDrag_data()
+{
+ QTest::addColumn<Qt::MouseButtons>("acceptedButtons");
+ QTest::addColumn<Qt::MouseButtons>("dragButton");
+ QTest::newRow("left: drag") << Qt::MouseButtons(Qt::LeftButton) << Qt::MouseButtons(Qt::LeftButton);
+ QTest::newRow("right: don't drag") << Qt::MouseButtons(Qt::LeftButton) << Qt::MouseButtons(Qt::RightButton);
+ QTest::newRow("left: don't drag") << Qt::MouseButtons(Qt::RightButton | Qt::MiddleButton) << Qt::MouseButtons(Qt::LeftButton);
+ QTest::newRow("right or middle: drag") << Qt::MouseButtons(Qt::RightButton | Qt::MiddleButton) << Qt::MouseButtons(Qt::MiddleButton);
+}
+
void tst_DragHandler::mouseDrag()
{
+ QFETCH(Qt::MouseButtons, acceptedButtons);
+ QFETCH(Qt::MouseButtons, dragButton);
+ bool shouldDrag = bool(acceptedButtons & dragButton);
+
const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
QScopedPointer<QQuickView> windowPtr;
createView(windowPtr, "draggables.qml");
@@ -206,6 +221,7 @@ void tst_DragHandler::mouseDrag()
QVERIFY(ball);
QQuickDragHandler *dragHandler = ball->findChild<QQuickDragHandler*>();
QVERIFY(dragHandler);
+ dragHandler->setAcceptedButtons(acceptedButtons); // QTBUG-76875
QSignalSpy translationChangedSpy(dragHandler, SIGNAL(translationChanged()));
QSignalSpy centroidChangedSpy(dragHandler, SIGNAL(centroidChanged()));
@@ -213,45 +229,57 @@ void tst_DragHandler::mouseDrag()
QPointF ballCenter = ball->clipRect().center();
QPointF scenePressPos = ball->mapToScene(ballCenter);
QPoint p1 = scenePressPos.toPoint();
- QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
+ QTest::mousePress(window, static_cast<Qt::MouseButton>(int(dragButton)), Qt::NoModifier, p1);
QVERIFY(!dragHandler->active());
- QCOMPARE(dragHandler->centroid().position(), ballCenter);
- QCOMPARE(dragHandler->centroid().pressPosition(), ballCenter);
- QCOMPARE(dragHandler->centroid().scenePosition(), scenePressPos);
- QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos);
- QCOMPARE(dragHandler->centroid().velocity(), QVector2D());
- QCOMPARE(centroidChangedSpy.count(), 1);
+ if (shouldDrag) {
+ QCOMPARE(dragHandler->centroid().position(), ballCenter);
+ QCOMPARE(dragHandler->centroid().pressPosition(), ballCenter);
+ QCOMPARE(dragHandler->centroid().scenePosition(), scenePressPos);
+ QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos);
+ QCOMPARE(dragHandler->centroid().velocity(), QVector2D());
+ QCOMPARE(centroidChangedSpy.count(), 1);
+ }
p1 += QPoint(dragThreshold, 0);
QTest::mouseMove(window, p1);
- QTRY_VERIFY(dragHandler->centroid().velocity().x() > 0);
- QCOMPARE(centroidChangedSpy.count(), 2);
- QVERIFY(!dragHandler->active());
+ if (shouldDrag) {
+ QTRY_VERIFY(dragHandler->centroid().velocity().x() > 0);
+ QCOMPARE(centroidChangedSpy.count(), 2);
+ QVERIFY(!dragHandler->active());
+ }
p1 += QPoint(1, 0);
QTest::mouseMove(window, p1);
- QTRY_VERIFY(dragHandler->active());
+ if (shouldDrag)
+ QTRY_VERIFY(dragHandler->active());
+ else
+ QVERIFY(!dragHandler->active());
QCOMPARE(translationChangedSpy.count(), 0);
- QCOMPARE(centroidChangedSpy.count(), 3);
+ if (shouldDrag)
+ QCOMPARE(centroidChangedSpy.count(), 3);
QCOMPARE(dragHandler->translation().x(), 0.0);
QPointF sceneGrabPos = p1;
- QCOMPARE(dragHandler->centroid().sceneGrabPosition(), sceneGrabPos);
+ if (shouldDrag)
+ QCOMPARE(dragHandler->centroid().sceneGrabPosition(), sceneGrabPos);
p1 += QPoint(19, 0);
QTest::mouseMove(window, p1);
- QTRY_VERIFY(dragHandler->active());
- QCOMPARE(dragHandler->centroid().position(), ballCenter);
- QCOMPARE(dragHandler->centroid().pressPosition(), ballCenter);
- QCOMPARE(dragHandler->centroid().scenePosition(), ball->mapToScene(ballCenter));
- QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos);
- QCOMPARE(dragHandler->centroid().sceneGrabPosition(), sceneGrabPos);
- QCOMPARE(dragHandler->translation().x(), dragThreshold + 20.0);
- QCOMPARE(dragHandler->translation().y(), 0.0);
- QVERIFY(dragHandler->centroid().velocity().x() > 0);
- QCOMPARE(centroidChangedSpy.count(), 4);
- QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
+ QVERIFY(shouldDrag ? dragHandler->active() : !dragHandler->active());
+ if (shouldDrag) {
+ QCOMPARE(dragHandler->centroid().position(), ballCenter);
+ QCOMPARE(dragHandler->centroid().pressPosition(), ballCenter);
+ QCOMPARE(dragHandler->centroid().scenePosition(), ball->mapToScene(ballCenter));
+ QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos);
+ QCOMPARE(dragHandler->centroid().sceneGrabPosition(), sceneGrabPos);
+ QCOMPARE(dragHandler->translation().x(), dragThreshold + 20.0);
+ QCOMPARE(dragHandler->translation().y(), 0.0);
+ QVERIFY(dragHandler->centroid().velocity().x() > 0);
+ QCOMPARE(centroidChangedSpy.count(), 4);
+ }
+ QTest::mouseRelease(window, static_cast<Qt::MouseButton>(int(dragButton)), Qt::NoModifier, p1);
QTRY_VERIFY(!dragHandler->active());
QCOMPARE(dragHandler->centroid().pressedButtons(), Qt::NoButton);
- QCOMPARE(ball->mapToScene(ballCenter).toPoint(), p1);
- QCOMPARE(translationChangedSpy.count(), 1);
- QCOMPARE(centroidChangedSpy.count(), 5);
+ if (shouldDrag)
+ QCOMPARE(ball->mapToScene(ballCenter).toPoint(), p1);
+ QCOMPARE(translationChangedSpy.count(), shouldDrag ? 1 : 0);
+ QCOMPARE(centroidChangedSpy.count(), shouldDrag ? 5 : 0);
}
void tst_DragHandler::dragFromMargin() // QTBUG-74966
diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml
index 221e7df139..042b730799 100644
--- a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml
+++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml
@@ -34,6 +34,7 @@ Rectangle {
property alias pressed: tap.pressed
property bool checked: false
property alias gesturePolicy: tap.gesturePolicy
+ property point tappedPosition: Qt.point(0, 0)
signal tapped
signal canceled
@@ -51,6 +52,7 @@ Rectangle {
longPressThreshold: 100 // CI can be insanely slow, so don't demand a timely release to generate onTapped
onTapped: {
tapFlash.start()
+ root.tappedPosition = point.scenePosition
root.tapped()
}
onCanceled: root.canceled()
diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp b/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp
index 33cea69147..e77ea97518 100644
--- a/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp
@@ -107,6 +107,8 @@ void tst_TapHandler::touchGesturePolicyDragThreshold()
QQuickItem *buttonDragThreshold = window->rootObject()->findChild<QQuickItem*>("DragThreshold");
QVERIFY(buttonDragThreshold);
+ QQuickTapHandler *tapHandler = buttonDragThreshold->findChild<QQuickTapHandler*>();
+ QVERIFY(tapHandler);
QSignalSpy dragThresholdTappedSpy(buttonDragThreshold, SIGNAL(tapped()));
// DragThreshold button stays pressed while touchpoint stays within dragThreshold, emits tapped on release
@@ -122,6 +124,8 @@ void tst_TapHandler::touchGesturePolicyDragThreshold()
QQuickTouchUtils::flush(window);
QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool());
QCOMPARE(dragThresholdTappedSpy.count(), 1);
+ QCOMPARE(buttonDragThreshold->property("tappedPosition").toPoint(), p1);
+ QCOMPARE(tapHandler->point().position(), QPointF());
// DragThreshold button is no longer pressed if touchpoint goes beyond dragThreshold
dragThresholdTappedSpy.clear();
@@ -152,6 +156,8 @@ void tst_TapHandler::mouseGesturePolicyDragThreshold()
QQuickItem *buttonDragThreshold = window->rootObject()->findChild<QQuickItem*>("DragThreshold");
QVERIFY(buttonDragThreshold);
+ QQuickTapHandler *tapHandler = buttonDragThreshold->findChild<QQuickTapHandler*>();
+ QVERIFY(tapHandler);
QSignalSpy dragThresholdTappedSpy(buttonDragThreshold, SIGNAL(tapped()));
// DragThreshold button stays pressed while mouse stays within dragThreshold, emits tapped on release
@@ -164,6 +170,8 @@ void tst_TapHandler::mouseGesturePolicyDragThreshold()
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool());
QTRY_COMPARE(dragThresholdTappedSpy.count(), 1);
+ QCOMPARE(buttonDragThreshold->property("tappedPosition").toPoint(), p1);
+ QCOMPARE(tapHandler->point().position(), QPointF());
// DragThreshold button is no longer pressed if mouse goes beyond dragThreshold
dragThresholdTappedSpy.clear();
diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
index 65a08ce87f..2314b82e8c 100644
--- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
+++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
@@ -1652,6 +1652,7 @@ void tst_qquickflickable::flickTwiceUsingTouches()
QQuickViewTestUtil::moveMouseAway(window.data());
window->show();
QVERIFY(window->rootObject() != nullptr);
+ QVERIFY(QTest::qWaitForWindowActive(window.data()));
QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
QVERIFY(flickable != nullptr);
@@ -1994,6 +1995,7 @@ void tst_qquickflickable::nestedMouseAreaUsingTouch()
QQuickViewTestUtil::moveMouseAway(window.data());
window->show();
QVERIFY(window->rootObject() != nullptr);
+ QVERIFY(QTest::qWaitForWindowActive(window.data()));
QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
QVERIFY(flickable != nullptr);
@@ -2489,6 +2491,7 @@ void tst_qquickflickable::synchronousDrag()
QQuickViewTestUtil::moveMouseAway(window);
window->show();
QVERIFY(window->rootObject() != nullptr);
+ QVERIFY(QTest::qWaitForWindowActive(window));
QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
QVERIFY(flickable != nullptr);
diff --git a/tests/auto/quick/qquicklistview/data/resizeAfterComponentComplete.qml b/tests/auto/quick/qquicklistview/data/resizeAfterComponentComplete.qml
new file mode 100644
index 0000000000..851d8f9a0c
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/resizeAfterComponentComplete.qml
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+
+ListView {
+ id: listView
+ property var lastItem
+ anchors.fill: parent
+ model: 10
+ delegate: Rectangle {
+ width: parent.width
+ height: 40
+ border.color: "lightsteelblue"
+ Text {
+ text: "Item" + (index + 1)
+ }
+ Component.onCompleted: {
+ if (index == 9)
+ listView.lastItem = this
+ }
+ }
+
+ populate: Transition {
+ NumberAnimation {
+ properties: "x,y"
+ duration: 1000
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index f14a6e75f6..bab2ec34f8 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -278,6 +278,7 @@ private slots:
void addOnCompleted();
void setPositionOnLayout();
void touchCancel();
+ void resizeAfterComponentComplete();
private:
template <class T> void items(const QUrl &source);
@@ -9020,6 +9021,21 @@ void tst_QQuickListView::touchCancel() // QTBUG-74679
QTRY_COMPARE(listview->contentY(), 500.0);
}
+void tst_QQuickListView::resizeAfterComponentComplete() // QTBUG-76487
+{
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("resizeAfterComponentComplete.qml"));
+ window->resize(640, 480);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QObject *listView = window->rootObject();
+ QVERIFY(listView);
+
+ QObject *lastItem = qvariant_cast<QObject *>(listView->property("lastItem"));
+ QTRY_COMPARE(lastItem->property("y").toInt(), 9 * lastItem->property("height").toInt());
+}
+
QTEST_MAIN(tst_QQuickListView)
#include "tst_qquicklistview.moc"