aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp8
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp19
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp15
-rw-r--r--src/qml/jsruntime/qv4object.cpp2
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp2
-rw-r--r--src/qml/jsruntime/qv4promiseobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4proxy.cpp24
-rw-r--r--src/qml/jsruntime/qv4reflect.cpp3
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp35
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp6
-rw-r--r--src/qml/types/qqmllistmodel.cpp8
-rw-r--r--src/quick/items/qquickmousearea.cpp6
-rw-r--r--src/quick/util/qquickanimation.cpp20
-rw-r--r--src/quick/util/qquickbehavior.cpp2
-rw-r--r--tests/auto/quick/qquickanimations/data/signalorder.qml27
-rw-r--r--tests/auto/quick/qquickanimations/qquickanimations.pro1
-rw-r--r--tests/auto/quick/qquickanimations/tst_qquickanimations.cpp43
-rw-r--r--tests/auto/quick/qquickbehaviors/data/delete.qml37
-rw-r--r--tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp11
-rw-r--r--tests/auto/quick/qquickmousearea/data/settingHiddenInPressUngrabs.qml36
-rw-r--r--tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp38
26 files changed, 312 insertions, 51 deletions
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index b5b421fa39..b67eceb7f7 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -361,7 +361,7 @@ ReturnedValue ArrayPrototype::method_toString(const FunctionObject *builtin, con
ScopedString string(scope, scope.engine->newString(QStringLiteral("join")));
ScopedFunctionObject f(scope, that->get(string));
if (f)
- return f->call(that, argv, argc);
+ return checkedResult(scope.engine, f->call(that, argv, argc));
return ObjectPrototype::method_toString(builtin, that, argv, argc);
}
@@ -1209,6 +1209,7 @@ ReturnedValue ArrayPrototype::method_every(const FunctionObject *b, const Value
arguments[1] = Value::fromDouble(k);
arguments[2] = instance;
r = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
ok = r->toBoolean();
}
return Encode(ok);
@@ -1276,6 +1277,7 @@ ReturnedValue ArrayPrototype::method_some(const FunctionObject *b, const Value *
arguments[1] = Value::fromDouble(k);
arguments[2] = instance;
result = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
if (result->toBoolean())
return Encode(true);
}
@@ -1345,6 +1347,7 @@ ReturnedValue ArrayPrototype::method_map(const FunctionObject *b, const Value *t
arguments[1] = Value::fromDouble(k);
arguments[2] = instance;
mapped = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
a->arraySet(k, mapped);
}
return a.asReturnedValue();
@@ -1380,6 +1383,7 @@ ReturnedValue ArrayPrototype::method_filter(const FunctionObject *b, const Value
arguments[1] = Value::fromDouble(k);
arguments[2] = instance;
selected = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
if (selected->toBoolean()) {
a->arraySet(to, arguments[0]);
++to;
@@ -1430,6 +1434,7 @@ ReturnedValue ArrayPrototype::method_reduce(const FunctionObject *b, const Value
arguments[2] = Value::fromDouble(k);
arguments[3] = instance;
acc = callback->call(nullptr, arguments, 4);
+ CHECK_EXCEPTION();
}
++k;
}
@@ -1483,6 +1488,7 @@ ReturnedValue ArrayPrototype::method_reduceRight(const FunctionObject *b, const
arguments[2] = Value::fromDouble(k - 1);
arguments[3] = instance;
acc = callback->call(nullptr, arguments, 4);
+ CHECK_EXCEPTION();
}
--k;
}
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index a13fb37a52..f643a1180f 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -1547,7 +1547,7 @@ ReturnedValue DatePrototype::method_toJSON(const FunctionObject *b, const Value
if (!toIso)
return v4->throwTypeError();
- return toIso->call(O, nullptr, 0);
+ return checkedResult(v4, toIso->call(O, nullptr, 0));
}
ReturnedValue DatePrototype::method_symbolToPrimitive(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 41a21ba379..fbc7897c67 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -357,7 +357,7 @@ ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, cons
return v4->throwTypeError();
thisObject = argc ? argv : nullptr;
if (argc < 2 || argv[1].isNullOrUndefined())
- return f->call(thisObject, argv, 0);
+ return checkedResult(v4, f->call(thisObject, argv, 0));
Object *arr = argv[1].objectValue();
if (!arr)
@@ -391,13 +391,14 @@ ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, cons
}
}
- return f->call(thisObject, arguments, len);
+ return checkedResult(v4, f->call(thisObject, arguments, len));
}
ReturnedValue FunctionPrototype::method_call(const QV4::FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
+ QV4::ExecutionEngine *v4 = b->engine();
if (!thisObject->isFunctionObject())
- return b->engine()->throwTypeError();
+ return v4->throwTypeError();
const FunctionObject *f = static_cast<const FunctionObject *>(thisObject);
@@ -406,7 +407,7 @@ ReturnedValue FunctionPrototype::method_call(const QV4::FunctionObject *b, const
++argv;
--argc;
}
- return f->call(thisObject, argv, argc);
+ return checkedResult(v4, f->call(thisObject, argv, argc));
}
ReturnedValue FunctionPrototype::method_bind(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
@@ -706,12 +707,12 @@ void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject
ReturnedValue BoundFunction::virtualCall(const FunctionObject *fo, const Value *, const Value *argv, int argc)
{
- const BoundFunction *f = static_cast<const BoundFunction *>(fo);
- Scope scope(f->engine());
-
- if (scope.hasException())
+ QV4::ExecutionEngine *v4 = fo->engine();
+ if (v4->hasException)
return Encode::undefined();
+ const BoundFunction *f = static_cast<const BoundFunction *>(fo);
+ Scope scope(v4);
Scoped<MemberData> boundArgs(scope, f->boundArgs());
ScopedFunctionObject target(scope, f->target());
JSCallData jsCallData(scope, (boundArgs ? boundArgs->size() : 0) + argc);
@@ -722,7 +723,7 @@ ReturnedValue BoundFunction::virtualCall(const FunctionObject *fo, const Value *
argp += boundArgs->size();
}
memcpy(argp, argv, argc*sizeof(Value));
- return target->call(jsCallData);
+ return checkedResult(v4, target->call(jsCallData));
}
ReturnedValue BoundFunction::virtualCallAsConstructor(const FunctionObject *fo, const Value *argv, int argc, const Value *)
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index e03d49c74d..ec250659bc 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -328,6 +328,10 @@ inline bool FunctionObject::isBoundFunction() const
return d()->vtable() == BoundFunction::staticVTable();
}
+inline ReturnedValue checkedResult(QV4::ExecutionEngine *v4, ReturnedValue result)
+{
+ return v4->hasException ? QV4::Encode::undefined() : result;
+}
}
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index 936c032fad..ce759111f4 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -703,6 +703,8 @@ QString Stringify::Str(const QString &key, const Value &v)
*jsCallData->thisObject = value;
jsCallData->args[0] = v4->newString(key);
value = toJSON->call(jsCallData);
+ if (v4->hasException)
+ return QString();
}
}
@@ -714,6 +716,8 @@ QString Stringify::Str(const QString &key, const Value &v)
jsCallData->args[1] = value;
*jsCallData->thisObject = holder;
value = replacerFunction->call(jsCallData);
+ if (v4->hasException)
+ return QString();
}
o = value->asReturnedValue();
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index f8999342d1..86b96e0e3c 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -304,7 +304,8 @@ ReturnedValue Lookup::getterAccessor(Lookup *l, ExecutionEngine *engine, const V
if (!getter->isFunctionObject()) // ### catch at resolve time
return Encode::undefined();
- return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0);
+ return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call(
+ &object, nullptr, 0));
}
}
l->getter = getterFallback;
@@ -321,7 +322,8 @@ ReturnedValue Lookup::getterProtoAccessor(Lookup *l, ExecutionEngine *engine, co
if (!getter->isFunctionObject()) // ### catch at resolve time
return Encode::undefined();
- return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0);
+ return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call(
+ &object, nullptr, 0));
}
return getterTwoClasses(l, engine, object);
}
@@ -341,7 +343,8 @@ ReturnedValue Lookup::getterProtoAccessorTwoClasses(Lookup *l, ExecutionEngine *
if (!getter->isFunctionObject()) // ### catch at resolve time
return Encode::undefined();
- return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0);
+ return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call(
+ &object, nullptr, 0));
}
}
l->getter = getterFallback;
@@ -386,7 +389,8 @@ ReturnedValue Lookup::primitiveGetterAccessor(Lookup *l, ExecutionEngine *engine
if (!getter->isFunctionObject()) // ### catch at resolve time
return Encode::undefined();
- return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0);
+ return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call(
+ &object, nullptr, 0));
}
}
l->getter = getterGeneric;
@@ -424,7 +428,8 @@ ReturnedValue Lookup::globalGetterProtoAccessor(Lookup *l, ExecutionEngine *engi
if (!getter->isFunctionObject()) // ### catch at resolve time
return Encode::undefined();
- return static_cast<const FunctionObject *>(getter)->call(engine->globalObject, nullptr, 0);
+ return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call(
+ engine->globalObject, nullptr, 0));
}
l->globalGetter = globalGetterGeneric;
return globalGetterGeneric(l, engine);
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 7dd0a247d6..fa24fde9c2 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -104,7 +104,7 @@ ReturnedValue Object::getValueAccessor(const Value &thisObject, const Value &v,
Scope scope(f->engine());
JSCallData jsCallData(scope);
*jsCallData->thisObject = thisObject;
- return f->call(jsCallData);
+ return checkedResult(scope.engine, f->call(jsCallData));
}
bool Object::putValue(uint memberIndex, PropertyAttributes attrs, const Value &value)
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index 6b4c3ba71a..c412f19a0a 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -666,7 +666,7 @@ ReturnedValue ObjectPrototype::method_toLocaleString(const FunctionObject *b, co
if (!f)
THROW_TYPE_ERROR();
- return f->call(thisObject, argv, argc);
+ return checkedResult(scope.engine, f->call(thisObject, argv, argc));
}
ReturnedValue ObjectPrototype::method_valueOf(const FunctionObject *b, const Value *thisObject, const Value *, int)
diff --git a/src/qml/jsruntime/qv4promiseobject.cpp b/src/qml/jsruntime/qv4promiseobject.cpp
index 40a0dfaa57..adb440b6a0 100644
--- a/src/qml/jsruntime/qv4promiseobject.cpp
+++ b/src/qml/jsruntime/qv4promiseobject.cpp
@@ -617,7 +617,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this
}
ScopedObject nextPromise(scope, Value::fromReturnedValue(resolve->call(thisObject, nextValue, 1)));
- if (!nextPromise || scope.hasException()) {
+ if (scope.hasException() || !nextPromise) {
ScopedValue completion(scope, Runtime::method_iteratorClose(e, iteratorObject, doneValue));
if (scope.hasException()) {
completion = e->exceptionValue->asReturnedValue();
@@ -763,7 +763,7 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi
}
ScopedObject nextPromise(scope, Value::fromReturnedValue(resolve->call(thisObject, nextValue, 1)));
- if (!nextPromise || scope.hasException()) {
+ if (scope.hasException() || !nextPromise) {
ScopedValue completion(scope, Runtime::method_iteratorClose(e, iteratorObject, doneValue));
if (scope.hasException()) {
completion = e->exceptionValue->asReturnedValue();
diff --git a/src/qml/jsruntime/qv4proxy.cpp b/src/qml/jsruntime/qv4proxy.cpp
index 9325e2e53b..8a76ed09fe 100644
--- a/src/qml/jsruntime/qv4proxy.cpp
+++ b/src/qml/jsruntime/qv4proxy.cpp
@@ -96,6 +96,8 @@ ReturnedValue ProxyObject::virtualGet(const Managed *m, PropertyKey id, const Va
cdata.args[2] = *receiver;
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
+ if (scope.engine->hasException)
+ return Encode::undefined();
ScopedProperty targetDesc(scope);
PropertyAttributes attributes = target->getOwnProperty(id, targetDesc);
if (attributes != Attr_Invalid && !attributes.isConfigurable()) {
@@ -136,7 +138,7 @@ bool ProxyObject::virtualPut(Managed *m, PropertyKey id, const Value &value, Val
cdata.args[3] = *receiver;
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
- if (!trapResult->toBoolean())
+ if (scope.engine->hasException || !trapResult->toBoolean())
return false;
ScopedProperty targetDesc(scope);
PropertyAttributes attributes = target->getOwnProperty(id, targetDesc);
@@ -176,7 +178,7 @@ bool ProxyObject::virtualDeleteProperty(Managed *m, PropertyKey id)
cdata.args[2] = o->d(); // ### fix receiver handling
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
- if (!trapResult->toBoolean())
+ if (scope.engine->hasException || !trapResult->toBoolean())
return false;
ScopedProperty targetDesc(scope);
PropertyAttributes attributes = target->getOwnProperty(id, targetDesc);
@@ -211,6 +213,8 @@ bool ProxyObject::virtualHasProperty(const Managed *m, PropertyKey id)
cdata.args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol();
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
+ if (scope.engine->hasException)
+ return false;
bool result = trapResult->toBoolean();
if (!result) {
ScopedProperty targetDesc(scope);
@@ -251,6 +255,8 @@ PropertyAttributes ProxyObject::virtualGetOwnProperty(const Managed *m, Property
cdata.args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol();
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
+ if (scope.engine->hasException)
+ return Attr_Invalid;
if (!trapResult->isObject() && !trapResult->isUndefined()) {
scope.engine->throwTypeError();
return Attr_Invalid;
@@ -323,7 +329,7 @@ bool ProxyObject::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Pro
cdata.args[2] = ObjectPrototype::fromPropertyDescriptor(scope.engine, p, attrs);
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
- bool result = trapResult->toBoolean();
+ bool result = !scope.engine->hasException && trapResult->toBoolean();
if (!result)
return false;
@@ -373,6 +379,8 @@ bool ProxyObject::virtualIsExtensible(const Managed *m)
cdata.args[0] = target;
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
+ if (scope.engine->hasException)
+ return false;
bool result = trapResult->toBoolean();
if (result != target->isExtensible()) {
scope.engine->throwTypeError();
@@ -404,6 +412,8 @@ bool ProxyObject::virtualPreventExtensions(Managed *m)
cdata.args[0] = target;
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
+ if (scope.engine->hasException)
+ return false;
bool result = trapResult->toBoolean();
if (result && target->isExtensible()) {
scope.engine->throwTypeError();
@@ -439,6 +449,8 @@ Heap::Object *ProxyObject::virtualGetPrototypeOf(const Managed *m)
cdata.args[0] = target;
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
+ if (scope.engine->hasException)
+ return nullptr;
if (!trapResult->isNull() && !trapResult->isObject()) {
scope.engine->throwTypeError();
return nullptr;
@@ -482,7 +494,7 @@ bool ProxyObject::virtualSetPrototypeOf(Managed *m, const Object *p)
cdata.args[1] = p ? p->asReturnedValue() : Encode::null();
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
- bool result = trapResult->toBoolean();
+ bool result = !scope.engine->hasException && trapResult->toBoolean();
if (!result)
return false;
if (!target->isExtensible()) {
@@ -573,6 +585,8 @@ OwnPropertyKeyIterator *ProxyObject::virtualOwnPropertyKeys(const Object *m, Val
JSCallData cdata(scope, 1, nullptr, handler);
cdata.args[0] = target;
ScopedObject trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
+ if (scope.engine->hasException)
+ return nullptr;
if (!trapResult) {
scope.engine->throwTypeError();
return nullptr;
@@ -699,7 +713,7 @@ ReturnedValue ProxyFunctionObject::virtualCall(const FunctionObject *f, const Va
if (scope.hasException())
return Encode::undefined();
if (trap->isNullOrUndefined())
- return target->call(thisObject, argv, argc);
+ return checkedResult(scope.engine, target->call(thisObject, argv, argc));
if (!trap->isFunctionObject())
return scope.engine->throwTypeError();
diff --git a/src/qml/jsruntime/qv4reflect.cpp b/src/qml/jsruntime/qv4reflect.cpp
index 15dcb602eb..3950fb139e 100644
--- a/src/qml/jsruntime/qv4reflect.cpp
+++ b/src/qml/jsruntime/qv4reflect.cpp
@@ -98,7 +98,8 @@ ReturnedValue Reflect::method_apply(const FunctionObject *f, const Value *, cons
if (scope.hasException())
return Encode::undefined();
- return static_cast<const FunctionObject &>(argv[0]).call(&argv[1], arguments.argv, arguments.argc);
+ return checkedResult(scope.engine, static_cast<const FunctionObject &>(argv[0]).call(
+ &argv[1], arguments.argv, arguments.argc));
}
ReturnedValue Reflect::method_construct(const FunctionObject *f, const Value *, const Value *argv, int argc)
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 39a2e96b45..2693384cdb 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -452,6 +452,8 @@ ReturnedValue RegExpPrototype::exec(ExecutionEngine *engine, const Object *o, co
ScopedFunctionObject exec(scope, o->get(key));
if (exec) {
ScopedValue result(scope, exec->call(o, s, 1));
+ if (scope.hasException())
+ RETURN_UNDEFINED();
if (!result->isNull() && !result->isObject())
return scope.engine->throwTypeError();
return result->asReturnedValue();
@@ -708,6 +710,8 @@ ReturnedValue RegExpPrototype::method_replace(const FunctionObject *f, const Val
cData->args[nCaptures + 1] = Encode(position);
cData->args[nCaptures + 2] = s;
ScopedValue replValue(scope, replaceFunction->call(cData));
+ if (scope.hasException())
+ return Encode::undefined();
replacement = replValue->toQString();
} else {
replacement = RegExp::getSubstitution(matchString->toQString(), s->toQString(), position, cData.args, nCaptures, replaceValue->toQString());
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 6a242ba5f6..57beaa8ccd 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -373,7 +373,7 @@ QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Val
return engine->throwTypeError();
ScopedValue result(scope, fHasInstance->call(&rval, &lval, 1));
- return Encode(result->toBoolean());
+ return scope.hasException() ? Encode::undefined() : Encode(result->toBoolean());
}
QV4::ReturnedValue Runtime::method_in(ExecutionEngine *engine, const Value &left, const Value &right)
@@ -489,6 +489,8 @@ ReturnedValue RuntimeHelpers::ordinaryToPrimitive(ExecutionEngine *engine, const
ScopedValue conv(scope, object->get(meth1));
if (FunctionObject *o = conv->as<FunctionObject>()) {
result = o->call(object, nullptr, 0);
+ if (engine->hasException)
+ return Encode::undefined();
if (result->isPrimitive())
return result->asReturnedValue();
}
@@ -499,6 +501,8 @@ ReturnedValue RuntimeHelpers::ordinaryToPrimitive(ExecutionEngine *engine, const
conv = object->get(meth2);
if (FunctionObject *o = conv->as<FunctionObject>()) {
result = o->call(object, nullptr, 0);
+ if (engine->hasException)
+ return Encode::undefined();
if (result->isPrimitive())
return result->asReturnedValue();
}
@@ -775,6 +779,8 @@ ReturnedValue Runtime::method_getIterator(ExecutionEngine *engine, const Value &
return engine->throwTypeError();
JSCallData cData(scope, 0, nullptr, o);
ScopedObject it(scope, f->call(cData));
+ if (engine->hasException)
+ return Encode::undefined();
if (!it)
return engine->throwTypeError();
return it->asReturnedValue();
@@ -1321,7 +1327,8 @@ ReturnedValue Runtime::method_callGlobalLookup(ExecutionEngine *engine, uint ind
return throwPropertyIsNotAFunctionTypeError(engine, &thisObject,
engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString());
- return static_cast<FunctionObject &>(function).call(&thisObject, argv, argc);
+ return checkedResult(engine, static_cast<FunctionObject &>(function).call(
+ &thisObject, argv, argc));
}
ReturnedValue Runtime::method_callQmlContextPropertyLookup(ExecutionEngine *engine, uint index, Value *argv, int argc)
@@ -1334,7 +1341,8 @@ ReturnedValue Runtime::method_callQmlContextPropertyLookup(ExecutionEngine *engi
return throwPropertyIsNotAFunctionTypeError(engine, thisObject,
engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString());
- return static_cast<FunctionObject &>(function).call(thisObject, argv, argc);
+ return checkedResult(engine, static_cast<FunctionObject &>(function).call(
+ thisObject, argv, argc));
}
ReturnedValue Runtime::method_callPossiblyDirectEval(ExecutionEngine *engine, Value *argv, int argc)
@@ -1353,7 +1361,7 @@ ReturnedValue Runtime::method_callPossiblyDirectEval(ExecutionEngine *engine, Va
if (function->d() == engine->evalFunction()->d())
return static_cast<EvalFunction *>(function.getPointer())->evalCall(thisObject, argv, argc, true);
- return function->call(thisObject, argv, argc);
+ return checkedResult(engine, function->call(thisObject, argv, argc));
}
ReturnedValue Runtime::method_callName(ExecutionEngine *engine, int nameIndex, Value *argv, int argc)
@@ -1371,7 +1379,7 @@ ReturnedValue Runtime::method_callName(ExecutionEngine *engine, int nameIndex, V
return throwPropertyIsNotAFunctionTypeError(engine, thisObject,
engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]->toQString());
- return f->call(thisObject, argv, argc);
+ return checkedResult(engine, f->call(thisObject, argv, argc));
}
ReturnedValue Runtime::method_callProperty(ExecutionEngine *engine, Value *base, int nameIndex, Value *argv, int argc)
@@ -1410,7 +1418,7 @@ ReturnedValue Runtime::method_callProperty(ExecutionEngine *engine, Value *base,
return engine->throwTypeError(error);
}
- return f->call(base, argv, argc);
+ return checkedResult(engine, f->call(base, argv, argc));
}
ReturnedValue Runtime::method_callPropertyLookup(ExecutionEngine *engine, Value *base, uint index, Value *argv, int argc)
@@ -1422,7 +1430,7 @@ ReturnedValue Runtime::method_callPropertyLookup(ExecutionEngine *engine, Value
if (!f.isFunctionObject())
return engine->throwTypeError();
- return static_cast<FunctionObject &>(f).call(base, argv, argc);
+ return checkedResult(engine, static_cast<FunctionObject &>(f).call(base, argv, argc));
}
ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, Value *base, const Value &index, Value *argv, int argc)
@@ -1439,7 +1447,7 @@ ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, Value *base,
if (!f)
return engine->throwTypeError();
- return f->call(base, argv, argc);
+ return checkedResult(engine, f->call(base, argv, argc));
}
ReturnedValue Runtime::method_callValue(ExecutionEngine *engine, const Value &func, Value *argv, int argc)
@@ -1447,14 +1455,16 @@ ReturnedValue Runtime::method_callValue(ExecutionEngine *engine, const Value &fu
if (!func.isFunctionObject())
return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow()));
Value undef = Value::undefinedValue();
- return static_cast<const FunctionObject &>(func).call(&undef, argv, argc);
+ return checkedResult(engine, static_cast<const FunctionObject &>(func).call(
+ &undef, argv, argc));
}
ReturnedValue Runtime::method_callWithReceiver(ExecutionEngine *engine, const Value &func, const Value *thisObject, Value *argv, int argc)
{
if (!func.isFunctionObject())
return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow()));
- return static_cast<const FunctionObject &>(func).call(thisObject, argv, argc);
+ return checkedResult(engine, static_cast<const FunctionObject &>(func).call(
+ thisObject, argv, argc));
}
struct CallArgs {
@@ -1508,7 +1518,8 @@ ReturnedValue Runtime::method_callWithSpread(ExecutionEngine *engine, const Valu
if (engine->hasException)
return Encode::undefined();
- return static_cast<const FunctionObject &>(function).call(&thisObject, arguments.argv, arguments.argc);
+ return checkedResult(engine, static_cast<const FunctionObject &>(function).call(
+ &thisObject, arguments.argv, arguments.argc));
}
ReturnedValue Runtime::method_construct(ExecutionEngine *engine, const Value &function, const Value &newTarget, Value *argv, int argc)
@@ -1551,7 +1562,7 @@ ReturnedValue Runtime::method_tailCall(CppStackFrame *frame, ExecutionEngine *en
if (!frame->callerCanHandleTailCall || !fo.canBeTailCalled() || engine->debugger()
|| unsigned(argc) > fo.formalParameterCount()) {
// Cannot tailcall, do a normal call:
- return fo.call(&thisObject, argv, argc);
+ return checkedResult(engine, fo.call(&thisObject, argv, argc));
}
memcpy(frame->jsFrame->args, argv, argc * sizeof(Value));
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index 6afa6d36d6..7a78e0a177 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -590,7 +590,7 @@ ReturnedValue StringPrototype::method_match(const FunctionObject *b, const Value
ScopedFunctionObject match(scope, that->get(scope.engine->symbol_match()));
if (!match)
return scope.engine->throwTypeError();
- return match->call(that, s, 1);
+ return checkedResult(scope.engine, match->call(that, s, 1));
}
ReturnedValue StringPrototype::method_normalize(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index faf7934c06..e1ef19e42b 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -765,6 +765,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_every(const FunctionObject *b
arguments[1] = Value::fromDouble(k);
arguments[2] = v;
r = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
ok = r->toBoolean();
}
return Encode(ok);
@@ -864,6 +865,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_filter(const FunctionObject *
arguments[1] = Value::fromDouble(k);
arguments[2] = instance;
selected = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
if (selected->toBoolean()) {
++arguments;
scope.alloc(1);
@@ -1203,6 +1205,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_map(const FunctionObject *b,
arguments[1] = Value::fromDouble(k);
arguments[2] = instance;
mapped = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
a->put(k, mapped);
}
return a->asReturnedValue();
@@ -1252,6 +1255,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_reduce(const FunctionObject *
arguments[2] = Value::fromDouble(k);
arguments[3] = instance;
acc = callback->call(nullptr, arguments, 4);
+ CHECK_EXCEPTION();
}
++k;
}
@@ -1307,6 +1311,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_reduceRight(const FunctionObj
arguments[2] = Value::fromDouble(k - 1);
arguments[3] = instance;
acc = callback->call(nullptr, arguments, 4);
+ CHECK_EXCEPTION();
}
--k;
}
@@ -1368,6 +1373,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_some(const FunctionObject *b,
arguments[1] = Value::fromDouble(k);
arguments[2] = instance;
result = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
if (result->toBoolean())
return Encode(true);
}
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
index 69b7876cf6..ff2a783dcd 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qml/types/qqmllistmodel.cpp
@@ -2780,10 +2780,12 @@ bool QQmlListModelParser::applyProperty(const QQmlRefPointer<QV4::CompiledData::
QV4::ScopedContext context(scope, QV4::QmlContext::create(v4->rootContext(), QQmlContextData::get(qmlContext(model->m_modelCache)), nullptr));
QV4::ScopedFunctionObject function(scope, QV4::FunctionObject::createScriptFunction(context, compilationUnit->runtimeFunctions[id]));
- QV4::ReturnedValue result = function->call(v4->globalObject, nullptr, 0);
-
QJSValue v;
- QJSValuePrivate::setValue(&v, v4, result);
+ QV4::ScopedValue result(scope, function->call(v4->globalObject, nullptr, 0));
+ if (v4->hasException)
+ v4->catchException();
+ else
+ QJSValuePrivate::setValue(&v, v4, result->asReturnedValue());
value.setValue<QJSValue>(v);
} else {
QByteArray script = scriptStr.toUtf8();
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index 5124802dbf..0cdd90d529 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -1079,6 +1079,12 @@ void QQuickMouseArea::itemChange(ItemChange change, const ItemChangeData &value)
}
setHovered(!d->hovered);
}
+ if (d->pressed && (!isVisible())) {
+ // This happens when the mouse area sets itself disabled or hidden
+ // inside the press handler. In that case we should not keep the internal
+ // state as pressed, since we never became the mouse grabber.
+ ungrabMouse();
+ }
break;
default:
break;
diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp
index 2043b50545..34942bdd9a 100644
--- a/src/quick/util/qquickanimation.cpp
+++ b/src/quick/util/qquickanimation.cpp
@@ -176,11 +176,8 @@ void QQuickAbstractAnimationPrivate::commence()
animationInstance = new QQuickAnimatorProxyJob(animationInstance, q);
animationInstance->addAnimationChangeListener(this, QAbstractAnimationJob::Completion);
}
+ emit q->started();
animationInstance->start();
- if (animationInstance->isStopped()) {
- running = false;
- emit q->stopped();
- }
}
}
@@ -293,10 +290,8 @@ void QQuickAbstractAnimation::setRunning(bool r)
d->animationInstance->setLoopCount(d->animationInstance->currentLoop() + d->loopCount);
supressStart = true; //we want the animation to continue, rather than restart
}
- if (!supressStart) {
+ if (!supressStart)
d->commence();
- emit started();
- }
} else {
if (d->paused) {
d->paused = false; //reset paused state to false when stopped
@@ -314,7 +309,16 @@ void QQuickAbstractAnimation::setRunning(bool r)
}
}
- emit runningChanged(d->running);
+
+ if (r == d->running) {
+ // This might happen if we start an animation with 0 duration: This will result in that
+ // commence() will emit started(), and then when it starts it will call setCurrentTime(0),
+ // (which is both start and end time of the animation), so it will also end up calling
+ // setRunning(false) (recursively) and stop the animation.
+ // Therefore, the state of d->running will in that case be different than r if we are back in
+ // the root stack frame of the recursive calls to setRunning()
+ emit runningChanged(d->running);
+ }
}
/*!
diff --git a/src/quick/util/qquickbehavior.cpp b/src/quick/util/qquickbehavior.cpp
index d9b13067ad..31c0ecddf6 100644
--- a/src/quick/util/qquickbehavior.cpp
+++ b/src/quick/util/qquickbehavior.cpp
@@ -143,7 +143,7 @@ void QQuickBehavior::setAnimation(QQuickAbstractAnimation *animation)
void QQuickBehaviorPrivate::animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State newState,QAbstractAnimationJob::State)
{
- if (!blockRunningChanged)
+ if (!blockRunningChanged && animation)
animation->notifyRunningChanged(newState == QAbstractAnimationJob::Running);
}
diff --git a/tests/auto/quick/qquickanimations/data/signalorder.qml b/tests/auto/quick/qquickanimations/data/signalorder.qml
new file mode 100644
index 0000000000..35029b0c84
--- /dev/null
+++ b/tests/auto/quick/qquickanimations/data/signalorder.qml
@@ -0,0 +1,27 @@
+import QtQuick 2.12
+
+
+Item {
+ id: wrapper
+ width: 400; height: 400
+
+ Rectangle {
+ id: greenRect
+ width: 50; height: 50
+ color: "red"
+
+ ColorAnimation on color {
+ id: colorAnimation
+ objectName: "ColorAnimation"
+ to: "green"
+ duration: 10
+ running: false
+ }
+
+ ParallelAnimation {
+ id: parallelAnimation
+ objectName: "ParallelAnimation"
+ running: false
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickanimations/qquickanimations.pro b/tests/auto/quick/qquickanimations/qquickanimations.pro
index 1c5494a24a..fa46cb422d 100644
--- a/tests/auto/quick/qquickanimations/qquickanimations.pro
+++ b/tests/auto/quick/qquickanimations/qquickanimations.pro
@@ -64,6 +64,7 @@ OTHER_FILES += \
data/scriptActionCrash.qml \
data/sequentialAnimationNullChildBug.qml \
data/signals.qml \
+ data/signalorder.qml \
data/transitionAssignmentBug.qml \
data/valuesource.qml \
data/valuesource2.qml
diff --git a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
index d9b42bdeb5..e0ce2d7134 100644
--- a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
+++ b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
@@ -89,6 +89,8 @@ private slots:
void easingProperties();
void rotation();
void startStopSignals();
+ void signalOrder_data();
+ void signalOrder();
void runningTrueBug();
void nonTransitionBug();
void registrationBug();
@@ -1292,6 +1294,47 @@ void tst_qquickanimations::startStopSignals()
QVERIFY(timer.elapsed() >= 200);
}
+void tst_qquickanimations::signalOrder_data()
+{
+ QTest::addColumn<QByteArray>("animationType");
+ QTest::addColumn<int>("duration");
+
+ QTest::addRow("ColorAnimation, duration = 10") << QByteArray("ColorAnimation") << 10;
+ QTest::addRow("ColorAnimation, duration = 0") << QByteArray("ColorAnimation") << 0;
+ QTest::addRow("ParallelAnimation, duration = 0") << QByteArray("ParallelAnimation") << 0;
+}
+
+void tst_qquickanimations::signalOrder()
+{
+ QFETCH(QByteArray, animationType);
+ QFETCH(int, duration);
+
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("signalorder.qml"));
+ QScopedPointer<QObject> obj(c.create());
+ auto *root = qobject_cast<QQuickItem *>(obj.data());
+ QVERIFY(root);
+ QQuickAbstractAnimation *animation = root->findChild<QQuickAbstractAnimation*>(animationType);
+ QVector<const char*> actualSignalOrder;
+ connect(animation, &QQuickAbstractAnimation::started , [&actualSignalOrder] () {
+ actualSignalOrder.append("started");
+ });
+ connect(animation, &QQuickAbstractAnimation::stopped , [&actualSignalOrder] () {
+ actualSignalOrder.append("stopped");
+ });
+ connect(animation, &QQuickAbstractAnimation::finished , [&actualSignalOrder] () {
+ actualSignalOrder.append("finished");
+ });
+ QSignalSpy finishedSpy(animation, SIGNAL(finished()));
+ if (QQuickColorAnimation *colorAnimation = qobject_cast<QQuickColorAnimation*>(animation))
+ colorAnimation->setDuration(duration);
+
+ animation->start();
+ QTRY_VERIFY(finishedSpy.count());
+ const QVector<const char*> expectedSignalOrder = { "started", "stopped", "finished" };
+ QCOMPARE(actualSignalOrder, expectedSignalOrder);
+}
+
void tst_qquickanimations::runningTrueBug()
{
//ensure we start correctly when "running: true" is explicitly set
diff --git a/tests/auto/quick/qquickbehaviors/data/delete.qml b/tests/auto/quick/qquickbehaviors/data/delete.qml
new file mode 100644
index 0000000000..1bf0267b84
--- /dev/null
+++ b/tests/auto/quick/qquickbehaviors/data/delete.qml
@@ -0,0 +1,37 @@
+import QtQuick 2.12
+
+Item {
+ visible: true
+ width: 640
+ height: 480
+
+ Component.onCompleted: {
+ myLoader.active = false
+ }
+
+ Loader {
+ id: myLoader
+
+ active: true
+ sourceComponent: Item {
+ width: 100
+ height: 100
+ id: myPopup
+
+ NumberAnimation {
+ id: anim
+ }
+
+ Rectangle {
+ color: "black"
+ Component.onCompleted: {
+ opacity = 20
+ }
+
+ Behavior on opacity {
+ animation: anim
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp b/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp
index fa9eba095d..8a962ce240 100644
--- a/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp
+++ b/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp
@@ -73,6 +73,7 @@ private slots:
void disabledWriteWhileRunning();
void aliasedProperty();
void innerBehaviorOverwritten();
+ void safeToDelete();
};
void tst_qquickbehaviors::simpleBehavior()
@@ -598,6 +599,16 @@ void tst_qquickbehaviors::innerBehaviorOverwritten()
QVERIFY(item->property("behaviorTriggered").toBool());
}
+// QTBUG-76749
+void tst_qquickbehaviors::safeToDelete()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("delete.qml"));
+ QVERIFY(c.create());
+}
+
+
+
QTEST_MAIN(tst_qquickbehaviors)
#include "tst_qquickbehaviors.moc"
diff --git a/tests/auto/quick/qquickmousearea/data/settingHiddenInPressUngrabs.qml b/tests/auto/quick/qquickmousearea/data/settingHiddenInPressUngrabs.qml
new file mode 100644
index 0000000000..4532dabfd8
--- /dev/null
+++ b/tests/auto/quick/qquickmousearea/data/settingHiddenInPressUngrabs.qml
@@ -0,0 +1,36 @@
+import QtQuick 2.11
+import QtQuick.Window 2.11
+
+Window {
+ id: window
+ visible: true
+ width: 200
+ height: 200
+
+ MouseArea {
+ objectName: "cat"
+ anchors.fill: parent
+ onPressed: visible = false
+ width: parent.width / 2
+ height: parent.height
+ Rectangle {
+ width: 10
+ height: 10
+ color: "blue"
+ }
+ }
+ MouseArea {
+ objectName: "mouse"
+ x: parent.width / 2
+ width: parent.width / 2
+ height: parent.height
+ onPressed: {
+ enabled = false
+ }
+ Rectangle {
+ width: 10
+ height: 10
+ color: "blue"
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
index 52d1458a53..0c44121830 100644
--- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
+++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
@@ -158,6 +158,7 @@ private slots:
void pressOneAndTapAnother();
void mask();
void nestedEventDelivery();
+ void settingHiddenInPressUngrabs();
private:
int startDragDistance() const {
@@ -2306,6 +2307,43 @@ void tst_QQuickMouseArea::nestedEventDelivery() // QTBUG-70898
QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50,150));
}
+void tst_QQuickMouseArea::settingHiddenInPressUngrabs()
+{
+ // When an item sets itself hidden, while handling pressed, it doesn't receive the grab.
+ // But that in turn means it doesn't see any release events, so we need to make sure it
+ // receives an ungrab event.
+
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("settingHiddenInPressUngrabs.qml"));
+ QScopedPointer<QQuickWindow> window(qmlobject_cast<QQuickWindow *>(c.create()));
+ QVERIFY(window.data());
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickMouseArea *catArea = window->findChild<QQuickMouseArea*>("cat");
+ QVERIFY(catArea != nullptr);
+ auto pointOnCatArea = catArea->mapToScene(QPointF(5.0, 5.0)).toPoint();
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, pointOnCatArea);
+
+ QCoreApplication::processEvents();
+ // The click hides the cat area
+ QTRY_VERIFY(!catArea->isVisible());
+ // The cat area is not stuck in pressed state.
+ QVERIFY(!catArea->pressed());
+
+ QQuickMouseArea *mouseArea = window->findChild<QQuickMouseArea*>("mouse");
+ QVERIFY(mouseArea != nullptr);
+ auto pointOnMouseArea = mouseArea->mapToScene(QPointF(5.0, 5.0)).toPoint();
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, pointOnMouseArea);
+
+ QCoreApplication::processEvents();
+ // The click disables the mouse area
+ QTRY_VERIFY(!mouseArea->isEnabled());
+ // The mouse area is not stuck in pressed state.
+ QVERIFY(!mouseArea->pressed());
+}
+
QTEST_MAIN(tst_QQuickMouseArea)
#include "tst_qquickmousearea.moc"