diff options
author | Liang Qi <liang.qi@qt.io> | 2018-09-06 07:30:06 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2018-09-06 07:30:06 +0200 |
commit | 60a2c3e453177389c0dfbca9211fa2918755124d (patch) | |
tree | 0f329b8ae854fa1a17be31a4653bb4b76af46f86 | |
parent | bbc52bcbb6391c4925df26672eb1f26040c6f67c (diff) | |
parent | fa74444ed06e4db21b0e9829a5832b886b39d372 (diff) |
Merge remote-tracking branch 'origin/5.12' into dev
Conflicts:
tools/qmlscene/main.cpp
Change-Id: Idd6e05582ade4def1a3907f9622a8e132bec6bf7
56 files changed, 1173 insertions, 232 deletions
diff --git a/src/imports/imports.pro b/src/imports/imports.pro index 653c787384..eb3e336c7f 100644 --- a/src/imports/imports.pro +++ b/src/imports/imports.pro @@ -3,10 +3,10 @@ TEMPLATE = subdirs SUBDIRS += \ builtins \ qtqml \ - folderlistmodel \ models \ labsmodels +qtConfig(thread): SUBDIRS += folderlistmodel qtHaveModule(sql): SUBDIRS += localstorage qtConfig(settings): SUBDIRS += settings qtConfig(statemachine): SUBDIRS += statemachine @@ -24,7 +24,7 @@ qtHaveModule(quick) { qtConfig(quick-particles): \ SUBDIRS += particles - qtConfig(quick-path): SUBDIRS += shapes + qtConfig(quick-path):qtConfig(thread): SUBDIRS += shapes } qtHaveModule(xmlpatterns) : SUBDIRS += xmllistmodel diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 0afd71767e..86fdf87650 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -1,5 +1,5 @@ TEMPLATE = subdirs QT_FOR_CONFIG += qml -qtConfig(qml-debug):SUBDIRS += qmltooling +qtConfig(thread):qtConfig(qml-debug):SUBDIRS += qmltooling qtHaveModule(quick):SUBDIRS += scenegraph diff --git a/src/plugins/qmltooling/qmltooling.pro b/src/plugins/qmltooling/qmltooling.pro index fd4a3eac65..30097be77b 100644 --- a/src/plugins/qmltooling/qmltooling.pro +++ b/src/plugins/qmltooling/qmltooling.pro @@ -6,9 +6,8 @@ SUBDIRS += \ packetprotocol # Connectors -SUBDIRS += \ - qmldbg_native \ - qmldbg_server +SUBDIRS += qmldbg_native +qtConfig(thread): SUBDIRS += qmldbg_server qmldbg_native.depends = packetprotocol qmldbg_server.depends = packetprotocol @@ -35,8 +34,9 @@ qmldbg_nativedebugger.depends = packetprotocol qtHaveModule(quick) { SUBDIRS += \ qmldbg_inspector \ - qmldbg_quickprofiler \ - qmldbg_preview + qmldbg_quickprofiler + + qtConfig(qml-network): SUBDIRS += qmldbg_preview qmldbg_inspector.depends = packetprotocol qmldbg_quickprofiler.depends = packetprotocol diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp index 4e82c7a062..ece2f0d692 100644 --- a/src/qml/animations/qabstractanimationjob.cpp +++ b/src/qml/animations/qabstractanimationjob.cpp @@ -70,17 +70,12 @@ QQmlAnimationTimer::QQmlAnimationTimer() : QQmlAnimationTimer *QQmlAnimationTimer::instance(bool create) { QQmlAnimationTimer *inst; -#ifndef QT_NO_THREAD if (create && !animationTimer()->hasLocalData()) { inst = new QQmlAnimationTimer; animationTimer()->setLocalData(inst); } else { inst = animationTimer() ? animationTimer()->localData() : 0; } -#else - static QQmlAnimationTimer unifiedTimer; - inst = &unifiedTimer; -#endif return inst; } diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 88accc2f49..883b21ab07 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -2279,42 +2279,38 @@ QV4::Compiler::Codegen::Reference JSCodeGen::fallbackNameLookup(const QString &n if (_scopeObject) { QQmlPropertyData *data = lookupQmlCompliantProperty(_scopeObject, name); - if (!data) - return Reference::fromName(this, name); - - Reference base = Reference::fromStackSlot(this, _qmlContextSlot); - Reference::PropertyCapturePolicy capturePolicy; - if (!data->isConstant() && !data->isQmlBinding()) - capturePolicy = Reference::CaptureAtRuntime; - else - capturePolicy = data->isConstant() ? Reference::DontCapture : Reference::CaptureAheadOfTime; - return Reference::fromQmlScopeObject(base, data->coreIndex(), data->notifyIndex(), capturePolicy); + if (data) { + Reference base = Reference::fromStackSlot(this, _qmlContextSlot); + Reference::PropertyCapturePolicy capturePolicy; + if (!data->isConstant() && !data->isQmlBinding()) + capturePolicy = Reference::CaptureAtRuntime; + else + capturePolicy = data->isConstant() ? Reference::DontCapture : Reference::CaptureAheadOfTime; + return Reference::fromQmlScopeObject(base, data->coreIndex(), data->notifyIndex(), capturePolicy); + } } if (_contextObject) { QQmlPropertyData *data = lookupQmlCompliantProperty(_contextObject, name); - if (!data) - return Reference::fromName(this, name); - - Reference base = Reference::fromStackSlot(this, _qmlContextSlot); - Reference::PropertyCapturePolicy capturePolicy; - if (!data->isConstant() && !data->isQmlBinding()) - capturePolicy = Reference::CaptureAtRuntime; - else - capturePolicy = data->isConstant() ? Reference::DontCapture : Reference::CaptureAheadOfTime; - return Reference::fromQmlContextObject(base, data->coreIndex(), data->notifyIndex(), capturePolicy); + if (data) { + Reference base = Reference::fromStackSlot(this, _qmlContextSlot); + Reference::PropertyCapturePolicy capturePolicy; + if (!data->isConstant() && !data->isQmlBinding()) + capturePolicy = Reference::CaptureAtRuntime; + else + capturePolicy = data->isConstant() ? Reference::DontCapture : Reference::CaptureAheadOfTime; + return Reference::fromQmlContextObject(base, data->coreIndex(), data->notifyIndex(), capturePolicy); + } } - if (m_globalNames.contains(name)) { - Reference r = Reference::fromName(this, name); + Reference r = Reference::fromName(this, name); + if (m_globalNames.contains(name)) r.global = true; - return r; - } + return r; #else Q_UNUSED(name) -#endif // V4_BOOTSTRAP - // fall back to name lookup at run-time. return Reference(); +#endif // V4_BOOTSTRAP } #ifndef V4_BOOTSTRAP diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 62dbcdaa7d..d61f79f0fc 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -2300,7 +2300,7 @@ Codegen::Reference Codegen::referenceForName(const QString &name, bool isLhs, co return fallback; Reference r = Reference::fromName(this, name); - r.global = (resolved.type == Context::ResolvedName::Global); + r.global = useFastLookups && (resolved.type == Context::ResolvedName::Global); return r; } @@ -2717,6 +2717,12 @@ bool Codegen::visit(ThisExpression *) if (hasError) return false; + if (_context->isArrowFunction) { + Reference r = referenceForName(QStringLiteral("this"), false); + r.isReadonly = true; + _expr.setResult(r); + return false; + } _expr.setResult(Reference::fromThis(this)); return false; } @@ -3996,7 +4002,7 @@ Codegen::Reference Codegen::Reference::baseObject() const if (rval.isAccumulator()) return Reference::fromAccumulator(codegen); if (rval.isStackSlot()) - Reference::fromStackSlot(codegen, rval.stackSlot()); + return Reference::fromStackSlot(codegen, rval.stackSlot()); if (rval.isConst()) return Reference::fromConst(codegen, rval.constantValue()); Q_UNREACHABLE(); @@ -4279,7 +4285,7 @@ QT_WARNING_POP return; } } - if (!disable_lookups && codegen->useFastLookups && global) { + if (!disable_lookups && global) { Instruction::LoadGlobalLookup load; load.index = codegen->registerGlobalGetterLookup(nameAsIndex()); codegen->bytecodeGenerator->addInstruction(load); diff --git a/src/qml/compiler/qv4compilercontext.cpp b/src/qml/compiler/qv4compilercontext.cpp index 4ee6d2c179..1b4c084ab4 100644 --- a/src/qml/compiler/qv4compilercontext.cpp +++ b/src/qml/compiler/qv4compilercontext.cpp @@ -241,6 +241,13 @@ void Context::emitBlockHeader(Codegen *codegen) Instruction::ConvertThisToObject convert; bytecodeGenerator->addInstruction(convert); } + if (innerFunctionAccessesThis) { + Instruction::LoadReg load; + load.reg = CallData::This; + bytecodeGenerator->addInstruction(load); + Codegen::Reference r = codegen->referenceForName(QStringLiteral("this"), true); + r.storeConsumeAccumulator(); + } if (contextType == ContextType::Global || (contextType == ContextType::Eval && !isStrict)) { // variables in global code are properties of the global context object, not locals as with other functions. diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h index 3df0aa6b3a..8713b0a188 100644 --- a/src/qml/compiler/qv4compilercontext_p.h +++ b/src/qml/compiler/qv4compilercontext_p.h @@ -201,6 +201,7 @@ struct Context { bool isArrowFunction = false; bool isGenerator = false; bool usesThis = false; + bool innerFunctionAccessesThis = false; bool hasTry = false; bool returnsClosure = false; mutable bool argumentsCanEscape = false; diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp index 5d3a7a6d8c..dafb1c360d 100644 --- a/src/qml/compiler/qv4compilerscanfunctions.cpp +++ b/src/qml/compiler/qv4compilerscanfunctions.cpp @@ -414,6 +414,17 @@ bool ScanFunctions::visit(TemplateLiteral *ast) } +bool ScanFunctions::visit(SuperLiteral *) +{ + Context *c = _context; + while (c && (c->contextType != ContextType::Function || c->isArrowFunction)) + c = c->parent; + + if (c) + c->requiresExecutionContext = true; + + return false; +} bool ScanFunctions::enterFunction(FunctionExpression *ast, bool enterName) { if (_context->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments"))) @@ -656,13 +667,16 @@ void ScanFunctions::calcEscapingVariables() Module *m = _cg->_module; for (Context *inner : qAsConst(m->contextMap)) { - if (inner->contextType == ContextType::Block && inner->usesArgumentsObject == Context::ArgumentsObjectUsed) { - Context *c = inner->parent; - while (c->contextType == ContextType::Block) - c = c->parent; + if (inner->usesArgumentsObject != Context::ArgumentsObjectUsed) + continue; + if (inner->contextType != ContextType::Block && !inner->isArrowFunction) + continue; + Context *c = inner->parent; + while (c && (c->contextType == ContextType::Block || c->isArrowFunction)) + c = c->parent; + if (c) c->usesArgumentsObject = Context::ArgumentsObjectUsed; - inner->usesArgumentsObject = Context::ArgumentsObjectNotUsed; - } + inner->usesArgumentsObject = Context::ArgumentsObjectNotUsed; } for (Context *inner : qAsConst(m->contextMap)) { if (!inner->parent || inner->usesArgumentsObject == Context::ArgumentsObjectUnknown) @@ -728,6 +742,8 @@ void ScanFunctions::calcEscapingVariables() } Q_ASSERT(c); c->hasDirectEval = true; + if (!c->isStrict) + c->innerFunctionAccessesThis = true; } Context *c = inner; while (c) { @@ -737,17 +753,26 @@ void ScanFunctions::calcEscapingVariables() } if (inner->usesThis) { inner->usesThis = false; - if (!inner->isStrict) { - Context *c = inner; - while (c->contextType == ContextType::Block) { - c = c->parent; - } - Q_ASSERT(c); - c->usesThis = true; + bool innerFunctionAccessesThis = false; + Context *c = inner; + while (c->contextType == ContextType::Block || c->isArrowFunction) { + innerFunctionAccessesThis |= c->isArrowFunction; + c = c->parent; } + Q_ASSERT(c); + if (!inner->isStrict) + c->usesThis = true; + c->innerFunctionAccessesThis |= innerFunctionAccessesThis; } } for (Context *c : qAsConst(m->contextMap)) { + if (c->innerFunctionAccessesThis) { + // add an escaping 'this' variable + c->addLocalVar(QStringLiteral("this"), Context::VariableDefinition, VariableScope::Let); + c->requiresExecutionContext = true; + auto m = c->members.find(QStringLiteral("this")); + m->canEscape = true; + } if (c->allVarsEscape && c->contextType == ContextType::Block && c->members.isEmpty()) c->allVarsEscape = false; if (c->contextType == ContextType::Global || (!c->isStrict && c->contextType == ContextType::Eval) || m->debugMode) @@ -787,6 +812,7 @@ void ScanFunctions::calcEscapingVariables() qDebug() << "==== escaping variables ===="; for (Context *c : qAsConst(m->contextMap)) { qDebug() << "Context" << c << c->name << "requiresExecutionContext" << c->requiresExecutionContext << "isStrict" << c->isStrict; + qDebug() << " isArrowFunction" << c->isArrowFunction << "innerFunctionAccessesThis" << c->innerFunctionAccessesThis; qDebug() << " parent:" << c->parent; if (c->argumentsCanEscape) qDebug() << " Arguments escape"; diff --git a/src/qml/compiler/qv4compilerscanfunctions_p.h b/src/qml/compiler/qv4compilerscanfunctions_p.h index 53b2336cb1..2e016b25b1 100644 --- a/src/qml/compiler/qv4compilerscanfunctions_p.h +++ b/src/qml/compiler/qv4compilerscanfunctions_p.h @@ -115,6 +115,7 @@ protected: bool visit(AST::ExpressionStatement *ast) override; bool visit(AST::FunctionExpression *ast) override; bool visit(AST::TemplateLiteral *ast) override; + bool visit(AST::SuperLiteral *) override; bool enterFunction(AST::FunctionExpression *ast, bool enterName); diff --git a/src/qml/configure.json b/src/qml/configure.json index 481cc553ae..1e3ac65f2a 100644 --- a/src/qml/configure.json +++ b/src/qml/configure.json @@ -32,10 +32,8 @@ "section": "QML", "condition": [ "features.commandlineparser", - "features.localserver", - "features.process", "features.qml-debug", - "features.qml-network", + "features.qml-network && features.localserver", "features.xmlstreamwriter" ], "output": [ "privateFeature" ] @@ -46,7 +44,7 @@ "section": "QML", "condition": [ "features.commandlineparser", - "features.localserver", + "features.qml-network && features.localserver", "features.process", "features.qml-debug" ], diff --git a/src/qml/doc/images/cpp-qml-integration-flowchart.odg b/src/qml/doc/images/cpp-qml-integration-flowchart.odg Binary files differindex 8482bd4bf4..f24021635e 100644 --- a/src/qml/doc/images/cpp-qml-integration-flowchart.odg +++ b/src/qml/doc/images/cpp-qml-integration-flowchart.odg diff --git a/src/qml/doc/images/cpp-qml-integration-flowchart.png b/src/qml/doc/images/cpp-qml-integration-flowchart.png Binary files differindex 56a33205fd..3649ff9e41 100644 --- a/src/qml/doc/images/cpp-qml-integration-flowchart.png +++ b/src/qml/doc/images/cpp-qml-integration-flowchart.png diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp index 9b5a983fdf..e74503e9d3 100644 --- a/src/qml/jsruntime/qv4arraybuffer.cpp +++ b/src/qml/jsruntime/qv4arraybuffer.cpp @@ -85,7 +85,7 @@ ReturnedValue SharedArrayBufferCtor::virtualCall(const FunctionObject *f, const } -ReturnedValue ArrayBufferCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *) +ReturnedValue ArrayBufferCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) { ExecutionEngine *v4 = f->engine(); Scope scope(v4); @@ -99,6 +99,12 @@ ReturnedValue ArrayBufferCtor::virtualCallAsConstructor(const FunctionObject *f, return v4->throwRangeError(QLatin1String("ArrayBuffer constructor: invalid length")); Scoped<ArrayBuffer> a(scope, v4->newArrayBuffer(len)); + if (newTarget->heapObject() != f->heapObject() && newTarget->isFunctionObject()) { + const FunctionObject *nt = static_cast<const FunctionObject *>(newTarget); + ScopedObject o(scope, nt->protoProperty()); + if (o) + a->setPrototypeOf(o); + } if (scope.engine->hasException) return Encode::undefined(); diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index c40d6414ff..7b1fd720a7 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -342,12 +342,8 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) uint index; ic = newInternalClass(QV4::FunctionPrototype::staticVTable(), objectPrototype()); - ic = ic->addMember(id_prototype()->propertyKey(), Attr_NotEnumerable, &index); - Q_ASSERT(index == Heap::FunctionObject::Index_Prototype); jsObjects[FunctionProto] = memoryManager->allocObject<FunctionPrototype>(ic->d()); ic = newInternalClass(FunctionObject::staticVTable(), functionPrototype()); - ic = ic->addMember(id_prototype()->propertyKey(), Attr_NotEnumerable|Attr_NotConfigurable, &index); - Q_ASSERT(index == Heap::FunctionObject::Index_Prototype); classes[Class_FunctionObject] = ic->d(); ic = ic->addMember(id_name()->propertyKey(), Attr_ReadOnly, &index); Q_ASSERT(index == Heap::ScriptFunction::Index_Name); diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index fe1ebbd556..ec041ab064 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -96,7 +96,7 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name, f->setName(name); if (createProto) - f->createDefaultPrototypeProperty(Heap::FunctionObject::Index_Prototype, Heap::FunctionObject::Index_ProtoConstructor); + f->createDefaultPrototypeProperty(Heap::FunctionObject::Index_ProtoConstructor); } @@ -130,8 +130,6 @@ void Heap::FunctionObject::init() Object::init(); this->scope.set(internalClass->engine, internalClass->engine->rootContext()->d()); - Q_ASSERT(internalClass && internalClass->find(internalClass->engine->id_prototype()->propertyKey()) == Index_Prototype); - setProperty(internalClass->engine, Index_Prototype, Primitive::undefinedValue()); } void Heap::FunctionObject::setFunction(Function *f) @@ -148,16 +146,15 @@ void Heap::FunctionObject::destroy() Object::destroy(); } -void FunctionObject::createDefaultPrototypeProperty(uint protoSlot, uint protoConstructorSlot) +void FunctionObject::createDefaultPrototypeProperty(uint protoConstructorSlot) { Scope s(this); - Q_ASSERT(internalClass() && internalClass()->find(s.engine->id_prototype()->propertyKey()) == protoSlot); Q_ASSERT(s.engine->internalClasses(EngineBase::Class_ObjectProto)->find(s.engine->id_constructor()->propertyKey()) == protoConstructorSlot); ScopedObject proto(s, s.engine->newObject(s.engine->internalClasses(EngineBase::Class_ObjectProto))); proto->setProperty(protoConstructorSlot, d()); - setProperty(protoSlot, proto); + defineDefaultProperty(s.engine->id_prototype(), proto, Attr_NotEnumerable|Attr_NotConfigurable); } ReturnedValue FunctionObject::name() const @@ -510,7 +507,7 @@ ReturnedValue ScriptFunction::virtualCall(const FunctionObject *fo, const Value return result; } -void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function, QV4::String *n) +void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function, QV4::String *n, bool makeConstructor) { FunctionObject::init(); this->scope.set(scope->engine(), scope->d()); @@ -524,7 +521,8 @@ void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function ScopedString name(s, n ? n->d() : function->name()); if (name) f->setName(name); - f->createDefaultPrototypeProperty(Heap::FunctionObject::Index_Prototype, Heap::FunctionObject::Index_ProtoConstructor); + if (makeConstructor && !function->isArrowFunction()) + f->createDefaultPrototypeProperty(Heap::FunctionObject::Index_ProtoConstructor); Q_ASSERT(internalClass && internalClass->find(s.engine->id_length()->propertyKey()) == Index_Length); setProperty(s.engine, Index_Length, Primitive::fromInt32(int(function->compiledFunction->length))); @@ -566,6 +564,7 @@ ReturnedValue ConstructorFunction::virtualCallAsConstructor(const FunctionObject v4->jsStackTop += frame.requiredJSStackFrameSize(); ReturnedValue result = Moth::VME::exec(&frame, v4); + ReturnedValue thisObject = frame.jsFrame->thisObject.asReturnedValue(); frame.pop(); @@ -573,9 +572,14 @@ ReturnedValue ConstructorFunction::virtualCallAsConstructor(const FunctionObject return Encode::undefined(); else if (Value::fromReturnedValue(result).isObject()) return result; - else if (!Value::fromReturnedValue(result).isUndefined() || frame.jsFrame->thisObject.isEmpty()) + else if (!Value::fromReturnedValue(result).isUndefined()) return v4->throwTypeError(); - return frame.jsFrame->thisObject.asReturnedValue(); + else if (Primitive::fromReturnedValue(thisObject).isEmpty()) { + Scope scope(v4); + ScopedString s(scope, v4->newString(QStringLiteral("this"))); + return v4->throwReferenceError(s); + } + return thisObject; } ReturnedValue ConstructorFunction::virtualCall(const FunctionObject *f, const Value *, const Value *, int) @@ -615,6 +619,7 @@ ReturnedValue DefaultClassConstructorFunction::virtualCallAsConstructor(const Fu // Do a super call ReturnedValue result = super->callAsConstructor(argv, argc, newTarget); + ReturnedValue thisObject = frame.jsFrame->thisObject.asReturnedValue(); frame.pop(); @@ -624,7 +629,13 @@ ReturnedValue DefaultClassConstructorFunction::virtualCallAsConstructor(const Fu return result; else if (!Value::fromReturnedValue(result).isUndefined()) return v4->throwTypeError(); - return frame.jsFrame->thisObject.asReturnedValue(); + else if (Primitive::fromReturnedValue(thisObject).isEmpty()) { + Scope scope(v4); + ScopedString s(scope, v4->newString(QStringLiteral("this"))); + return v4->throwReferenceError(s); + } + + return thisObject; } ReturnedValue DefaultClassConstructorFunction::virtualCall(const FunctionObject *f, const Value *, const Value *, int) diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 766960d2ac..43f4921875 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -76,7 +76,6 @@ namespace Heap { DECLARE_HEAP_OBJECT(FunctionObject, Object) { DECLARE_MARKOBJECTS(FunctionObject); enum { - Index_Prototype = 0, Index_ProtoConstructor = 0 }; @@ -116,10 +115,10 @@ struct IndexedBuiltinFunction : FunctionObject { DECLARE_HEAP_OBJECT(ScriptFunction, FunctionObject) { DECLARE_MARKOBJECTS(ScriptFunction) enum { - Index_Name = FunctionObject::Index_Prototype + 1, + Index_Name, Index_Length }; - void init(QV4::ExecutionContext *scope, Function *function, QV4::String *name = nullptr); + void init(QV4::ExecutionContext *scope, Function *function, QV4::String *name = nullptr, bool makeConstructor = true); }; #define MemberFunctionMembers(class, Member) \ @@ -127,6 +126,10 @@ DECLARE_HEAP_OBJECT(ScriptFunction, FunctionObject) { DECLARE_HEAP_OBJECT(MemberFunction, ScriptFunction) { DECLARE_MARKOBJECTS(MemberFunction) + + void init(QV4::ExecutionContext *scope, Function *function, QV4::String *name = nullptr) { + ScriptFunction::init(scope, function, name, false); + } }; struct ConstructorFunction : MemberFunction @@ -173,7 +176,7 @@ struct Q_QML_EXPORT FunctionObject: Object { void setName(String *name) { defineReadonlyConfigurableProperty(engine()->id_name(), *name); } - void createDefaultPrototypeProperty(uint protoSlot, uint protoConstructorSlot); + void createDefaultPrototypeProperty(uint protoConstructorSlot); inline ReturnedValue callAsConstructor(const JSCallData &data) const; ReturnedValue callAsConstructor(const Value *argv, int argc, const Value *newTarget = nullptr) const { diff --git a/src/qml/jsruntime/qv4generatorobject_p.h b/src/qml/jsruntime/qv4generatorobject_p.h index 55e6091ad5..c3b8e84154 100644 --- a/src/qml/jsruntime/qv4generatorobject_p.h +++ b/src/qml/jsruntime/qv4generatorobject_p.h @@ -73,6 +73,9 @@ struct GeneratorFunctionCtor : FunctionObject { }; struct GeneratorFunction : ScriptFunction { + void init(QV4::ExecutionContext *scope, Function *function, QV4::String *name = nullptr) { + ScriptFunction::init(scope, function, name, false); + } }; struct MemberGeneratorFunction : MemberFunction { diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp index 8158d8ddd9..3eaf760792 100644 --- a/src/qml/jsruntime/qv4objectiterator.cpp +++ b/src/qml/jsruntime/qv4objectiterator.cpp @@ -128,7 +128,10 @@ DEFINE_OBJECT_VTABLE(ForInIteratorObject); void Heap::ForInIteratorObject::markObjects(Heap::Base *that, MarkStack *markStack) { ForInIteratorObject *o = static_cast<ForInIteratorObject *>(that); - o->object->mark(markStack); + if (o->object) + o->object->mark(markStack); + if (o->current) + o->current->mark(markStack); o->workArea[0].mark(markStack); o->workArea[1].mark(markStack); Object::markObjects(that, markStack); diff --git a/src/qml/jsruntime/qv4propertykey.cpp b/src/qml/jsruntime/qv4propertykey.cpp index 12a3653034..361ade17c2 100644 --- a/src/qml/jsruntime/qv4propertykey.cpp +++ b/src/qml/jsruntime/qv4propertykey.cpp @@ -42,6 +42,7 @@ #include <QtCore/qstring.h> #include <qv4string_p.h> #include <qv4engine_p.h> +#include <qv4scopedvalue_p.h> QV4::Heap::StringOrSymbol *QV4::PropertyKey::toStringOrSymbol(QV4::ExecutionEngine *e) { @@ -60,6 +61,24 @@ bool QV4::PropertyKey::isSymbol() const { return s && !s->internalClass->vtable->isString && s->internalClass->vtable->isStringOrSymbol; } +bool QV4::PropertyKey::isCanonicalNumericIndexString() const +{ + if (isArrayIndex()) + return true; + if (isSymbol()) + return false; + Heap::String *s = static_cast<Heap::String *>(asStringOrSymbol()); + Scope scope(s->internalClass->engine); + ScopedString str(scope, s); + double d = str->toNumber(); + if (d == 0. && std::signbit(d)) + return true; + ScopedString converted(scope, Primitive::fromDouble(d).toString(scope.engine)); + if (converted->equals(str)) + return true; + return false; +} + QString QV4::PropertyKey::toQString() const { if (isArrayIndex()) diff --git a/src/qml/jsruntime/qv4propertykey_p.h b/src/qml/jsruntime/qv4propertykey_p.h index 7134b06c6d..cb2661f244 100644 --- a/src/qml/jsruntime/qv4propertykey_p.h +++ b/src/qml/jsruntime/qv4propertykey_p.h @@ -126,6 +126,7 @@ public: bool isString() const; bool isSymbol() const; + bool isCanonicalNumericIndexString() const; Q_QML_EXPORT QString toQString() const; Heap::StringOrSymbol *toStringOrSymbol(ExecutionEngine *e); diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index 7492f8872d..a07443077e 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -280,11 +280,20 @@ void Heap::TypedArrayCtor::init(QV4::ExecutionContext *scope, TypedArray::Type t type = t; } -ReturnedValue TypedArrayCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *) +ReturnedValue TypedArrayCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) { Scope scope(f->engine()); const TypedArrayCtor *that = static_cast<const TypedArrayCtor *>(f); + auto updateProto = [=](Scope &scope, Scoped<TypedArray> &a) { + if (newTarget->heapObject() != f->heapObject() && newTarget->isFunctionObject()) { + const FunctionObject *nt = static_cast<const FunctionObject *>(newTarget); + ScopedObject o(scope, nt->protoProperty()); + if (o) + a->setPrototypeOf(o); + } + }; + if (!argc || !argv[0].isObject()) { // ECMA 6 22.2.1.1 qint64 l = argc ? argv[0].toIndex() : 0; @@ -306,6 +315,7 @@ ReturnedValue TypedArrayCtor::virtualCallAsConstructor(const FunctionObject *f, array->d()->byteLength = byteLength; array->d()->byteOffset = 0; + updateProto(scope, array); return array.asReturnedValue(); } Scoped<TypedArray> typedArray(scope, argc ? argv[0] : Primitive::undefinedValue()); @@ -346,6 +356,7 @@ ReturnedValue TypedArrayCtor::virtualCallAsConstructor(const FunctionObject *f, } } + updateProto(scope, array); return array.asReturnedValue(); } Scoped<ArrayBuffer> buffer(scope, argc ? argv[0] : Primitive::undefinedValue()); @@ -383,6 +394,8 @@ ReturnedValue TypedArrayCtor::virtualCallAsConstructor(const FunctionObject *f, array->d()->buffer.set(scope.engine, buffer->d()); array->d()->byteLength = byteLength; array->d()->byteOffset = byteOffset; + + updateProto(scope, array); return array.asReturnedValue(); } @@ -421,7 +434,7 @@ ReturnedValue TypedArrayCtor::virtualCallAsConstructor(const FunctionObject *f, b += elementSize; } - + updateProto(scope, array); return array.asReturnedValue(); } @@ -446,22 +459,26 @@ Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type ReturnedValue TypedArray::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty) { - if (!id.isArrayIndex()) + uint index = id.asArrayIndex(); + if (index == UINT_MAX && !id.isCanonicalNumericIndexString()) return Object::virtualGet(m, id, receiver, hasProperty); + // fall through, with index == UINT_MAX it'll do the right thing. - uint index = id.asArrayIndex(); Scope scope(static_cast<const Object *>(m)->engine()); Scoped<TypedArray> a(scope, static_cast<const TypedArray *>(m)); if (a->d()->buffer->isDetachedBuffer()) return scope.engine->throwTypeError(); - uint bytesPerElement = a->d()->type->bytesPerElement; - uint byteOffset = a->d()->byteOffset + index * bytesPerElement; - if (byteOffset + bytesPerElement > (uint)a->d()->buffer->byteLength()) { + if (index >= a->length()) { if (hasProperty) *hasProperty = false; return Encode::undefined(); } + + uint bytesPerElement = a->d()->type->bytesPerElement; + uint byteOffset = a->d()->byteOffset + index * bytesPerElement; + Q_ASSERT(byteOffset + bytesPerElement <= (uint)a->d()->buffer->byteLength()); + if (hasProperty) *hasProperty = true; return a->d()->type->read(a->d()->buffer->data->data() + byteOffset); @@ -469,17 +486,42 @@ ReturnedValue TypedArray::virtualGet(const Managed *m, PropertyKey id, const Val bool TypedArray::virtualHasProperty(const Managed *m, PropertyKey id) { + uint index = id.asArrayIndex(); + if (index == UINT_MAX && !id.isCanonicalNumericIndexString()) + return Object::virtualHasProperty(m, id); + // fall through, with index == UINT_MAX it'll do the right thing. + + const TypedArray *a = static_cast<const TypedArray *>(m); + if (a->d()->buffer->isDetachedBuffer()) { + a->engine()->throwTypeError(); + return false; + } + if (index >= a->length()) + return false; + return true; +} + +PropertyAttributes TypedArray::virtualGetOwnProperty(Managed *m, PropertyKey id, Property *p) +{ + uint index = id.asArrayIndex(); + if (index == UINT_MAX && !id.isCanonicalNumericIndexString()) + return Object::virtualGetOwnProperty(m, id, p); + // fall through, with index == UINT_MAX it'll do the right thing. + bool hasProperty = false; - virtualGet(m, id, nullptr, &hasProperty); - return hasProperty; + ReturnedValue v = virtualGet(m, id, m, &hasProperty); + if (p) + p->value = v; + return hasProperty ? Attr_NotConfigurable : PropertyAttributes(); } bool TypedArray::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver) { - if (!id.isArrayIndex()) + uint index = id.asArrayIndex(); + if (index == UINT_MAX && !id.isCanonicalNumericIndexString()) return Object::virtualPut(m, id, value, receiver); + // fall through, with index == UINT_MAX it'll do the right thing. - uint index = id.asArrayIndex(); ExecutionEngine *v4 = static_cast<Object *>(m)->engine(); if (v4->hasException) return false; @@ -489,10 +531,12 @@ bool TypedArray::virtualPut(Managed *m, PropertyKey id, const Value &value, Valu if (a->d()->buffer->isDetachedBuffer()) return scope.engine->throwTypeError(); + if (index >= a->length()) + return false; + uint bytesPerElement = a->d()->type->bytesPerElement; uint byteOffset = a->d()->byteOffset + index * bytesPerElement; - if (byteOffset + bytesPerElement > (uint)a->d()->buffer->byteLength()) - return false; + Q_ASSERT(byteOffset + bytesPerElement <= (uint)a->d()->buffer->byteLength()); Value v = Primitive::fromReturnedValue(value.convertedToNumber()); if (scope.hasException() || a->d()->buffer->isDetachedBuffer()) @@ -501,6 +545,37 @@ bool TypedArray::virtualPut(Managed *m, PropertyKey id, const Value &value, Valu return true; } +bool TypedArray::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property *p, PropertyAttributes attrs) +{ + uint index = id.asArrayIndex(); + if (index == UINT_MAX && !id.isCanonicalNumericIndexString()) + return Object::virtualDefineOwnProperty(m, id, p, attrs); + // fall through, with index == UINT_MAX it'll do the right thing. + + TypedArray *a = static_cast<TypedArray *>(m); + if (index >= a->length() || attrs.isAccessor()) + return false; + + if (attrs.hasConfigurable() && attrs.isConfigurable()) + return false; + if (attrs.hasEnumerable() && !attrs.isEnumerable()) + return false; + if (attrs.hasWritable() && !attrs.isWritable()) + return false; + if (!p->value.isEmpty()) { + ExecutionEngine *engine = a->engine(); + + Value v = Primitive::fromReturnedValue(p->value.convertedToNumber()); + if (engine->hasException || a->d()->buffer->isDetachedBuffer()) + return engine->throwTypeError(); + uint bytesPerElement = a->d()->type->bytesPerElement; + uint byteOffset = a->d()->byteOffset + index * bytesPerElement; + Q_ASSERT(byteOffset + bytesPerElement <= (uint)a->d()->buffer->byteLength()); + a->d()->type->write(a->d()->buffer->data->data() + byteOffset, v); + } + return true; +} + void TypedArrayPrototype::init(ExecutionEngine *engine, TypedArrayCtor *ctor) { Scope scope(engine); diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h index 909334adb0..ad0953ed0c 100644 --- a/src/qml/jsruntime/qv4typedarray_p.h +++ b/src/qml/jsruntime/qv4typedarray_p.h @@ -167,7 +167,10 @@ struct Q_QML_PRIVATE_EXPORT TypedArray : Object static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty); static bool virtualHasProperty(const Managed *m, PropertyKey id); + static PropertyAttributes virtualGetOwnProperty(Managed *m, PropertyKey id, Property *p); static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver); + static bool virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property *p, PropertyAttributes attrs); + }; struct IntrinsicTypedArrayCtor: FunctionObject diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp index 96313d7627..2ef1dc7e93 100644 --- a/src/qml/qml/ftw/qqmlthread.cpp +++ b/src/qml/qml/ftw/qqmlthread.cpp @@ -316,6 +316,12 @@ void QQmlThread::shutdownThread() void QQmlThread::internalCallMethodInThread(Message *message) { +#if !QT_CONFIG(thread) + message->call(this); + delete message; + return; +#endif + Q_ASSERT(!isThisThread()); d->lock(); Q_ASSERT(d->m_mainThreadWaiting == false); @@ -376,6 +382,10 @@ void QQmlThread::internalCallMethodInMain(Message *message) void QQmlThread::internalPostMethodToThread(Message *message) { +#if !QT_CONFIG(thread) + internalPostMethodToMain(message); + return; +#endif Q_ASSERT(!isThisThread()); d->lock(); bool wasEmpty = d->threadList.isEmpty(); diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 26187ca086..82a3f45784 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -95,7 +95,9 @@ #include <private/qqmldelegatemodel_p.h> #endif #include <private/qqmlobjectmodel_p.h> +#if QT_CONFIG(thread) #include <private/qquickworkerscript_p.h> +#endif #include <private/qqmlinstantiator_p.h> #include <private/qqmlloggingcategory_p.h> @@ -243,7 +245,9 @@ void QQmlEnginePrivate::registerQtQuick2Types(const char *uri, int versionMajor, qmlRegisterType<QQmlListElement>(uri, versionMajor, versionMinor, "ListElement"); // Now in QtQml.Models, here for compatibility qmlRegisterCustomType<QQmlListModel>(uri, versionMajor, versionMinor, "ListModel", new QQmlListModelParser); // Now in QtQml.Models, here for compatibility #endif +#if QT_CONFIG(thread) qmlRegisterType<QQuickWorkerScript>(uri, versionMajor, versionMinor, "WorkerScript"); +#endif qmlRegisterType<QQuickPackage>(uri, versionMajor, versionMinor, "Package"); #if QT_CONFIG(qml_delegate_model) qmlRegisterType<QQmlDelegateModel>(uri, versionMajor, versionMinor, "VisualDataModel"); @@ -687,7 +691,9 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e) #endif outputWarningsToMsgLog(true), cleanup(nullptr), erroredBindings(nullptr), inProgressCreations(0), +#if QT_CONFIG(thread) workerScriptEngine(nullptr), +#endif activeObjectCreator(nullptr), #if QT_CONFIG(qml_network) networkAccessManager(nullptr), networkAccessManagerFactory(nullptr), @@ -987,6 +993,7 @@ void QQmlEnginePrivate::init() rootContext = new QQmlContext(q,true); } +#if QT_CONFIG(thread) QQuickWorkerScriptEngine *QQmlEnginePrivate::getWorkerScriptEngine() { Q_Q(QQmlEngine); @@ -994,6 +1001,7 @@ QQuickWorkerScriptEngine *QQmlEnginePrivate::getWorkerScriptEngine() workerScriptEngine = new QQuickWorkerScriptEngine(q); return workerScriptEngine; } +#endif /*! \class QQmlEngine diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index f606896953..d05f6634ec 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -153,8 +153,10 @@ public: QV8Engine *v8engine() const { return q_func()->handle()->v8Engine; } QV4::ExecutionEngine *v4engine() const { return q_func()->handle(); } +#if QT_CONFIG(thread) QQuickWorkerScriptEngine *getWorkerScriptEngine(); QQuickWorkerScriptEngine *workerScriptEngine; +#endif QUrl baseUrl; diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 1c37894751..ee6484f0b7 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -674,6 +674,7 @@ bool QQmlImportInstance::setQmldirContent(const QString &resolvedUrl, const QQml { Q_ASSERT(resolvedUrl.endsWith(Slash)); url = resolvedUrl; + localDirectoryPath = QQmlFile::urlToLocalFileOrQrc(url); qmlDirComponents = qmldir.components(); @@ -811,21 +812,20 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt *type_return = returnType; return returnType.isValid(); } - } else if (!isLibrary) { + } else if (!isLibrary && !localDirectoryPath.isEmpty()) { QString qmlUrl; bool exists = false; const QString urlsToTry[2] = { - url + QString::fromRawData(type.constData(), type.length()) + dotqml_string, // Type -> Type.qml - url + QString::fromRawData(type.constData(), type.length()) + dotuidotqml_string // Type -> Type.ui.qml + typeStr + dotqml_string, // Type -> Type.qml + typeStr + dotuidotqml_string // Type -> Type.ui.qml }; for (uint i = 0; i < sizeof(urlsToTry) / sizeof(urlsToTry[0]); ++i) { - const QString url = urlsToTry[i]; - const QString localPath = QQmlFile::urlToLocalFileOrQrc(url); - exists = !typeLoader->absoluteFilePath(localPath).isEmpty(); + exists = typeLoader->fileExists(localDirectoryPath, urlsToTry[i]); if (exists) { +#if defined(Q_OS_MACOS) || defined(Q_OS_WIN) // don't let function.qml confuse the use of "new Function(...)" for example. - if (!QQml_isFileCaseCorrect(localPath)) { + if (!QQml_isFileCaseCorrect(localDirectoryPath + urlsToTry[i])) { exists = false; if (errors) { QQmlError caseError; @@ -834,7 +834,10 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt } break; } - qmlUrl = url; +#else + Q_UNUSED(errors); +#endif + qmlUrl = url + urlsToTry[i]; break; } } @@ -1433,6 +1436,7 @@ QQmlImportInstance *QQmlImportsPrivate::addImportToNamespace(QQmlImportNamespace QQmlImportInstance *import = new QQmlImportInstance; import->uri = uri; import->url = url; + import->localDirectoryPath = QQmlFile::urlToLocalFileOrQrc(url); import->majversion = vmaj; import->minversion = vmin; import->isLibrary = (type == QV4::CompiledData::Import::ImportLibrary); @@ -1770,8 +1774,14 @@ QQmlImportDatabase::QQmlImportDatabase(QQmlEngine *e) { filePluginPath << QLatin1String("."); // Search order is applicationDirPath(), qrc:/qt-project.org/imports, $QML2_IMPORT_PATH, QLibraryInfo::Qml2ImportsPath +#ifndef Q_OS_WASM + QString installImportsPath = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath); +#else + // Hardcode the qml imports to "qml/" relative to the app exe. + // This should perhaps be set via Qml2Imports in qt.conf. + QString installImportsPath = QStringLiteral("qml/"); +#endif - QString installImportsPath = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath); addImportPath(installImportsPath); // env import paths diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h index 283bd40660..f8c01ed876 100644 --- a/src/qml/qml/qqmlimport_p.h +++ b/src/qml/qml/qqmlimport_p.h @@ -78,6 +78,7 @@ struct QQmlImportInstance { QString uri; // e.g. QtQuick QString url; // the base path of the import + QString localDirectoryPath; // the base path of the import if it's a local file int majversion; // the major version imported int minversion; // the minor version imported bool isLibrary; // true means that this is not a file import diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 739280bbfe..0b0ee9cb9a 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -865,13 +865,23 @@ void QQmlTypeLoaderThread::loadWithCachedUnitAsync(QQmlDataBlob *b, const QV4::C void QQmlTypeLoaderThread::callCompleted(QQmlDataBlob *b) { b->addref(); +#if !QT_CONFIG(thread) + if (!isThisThread()) + postMethodToThread(&This::callCompletedMain, b); +#else postMethodToMain(&This::callCompletedMain, b); +#endif } void QQmlTypeLoaderThread::callDownloadProgressChanged(QQmlDataBlob *b, qreal p) { b->addref(); +#if !QT_CONFIG(thread) + if (!isThisThread()) + postMethodToThread(&This::callDownloadProgressChangedMain, b, p); +#else postMethodToMain(&This::callDownloadProgressChangedMain, b, p); +#endif } void QQmlTypeLoaderThread::initializeEngine(QQmlExtensionInterface *iface, @@ -1755,10 +1765,14 @@ Returns a QQmlQmldirData for \a url. The QQmlQmldirData may be cached. */ QQmlRefPointer<QQmlQmldirData> QQmlTypeLoader::getQmldir(const QUrl &url) { +#ifndef Q_OS_WASM Q_ASSERT(!url.isRelative() && (QQmlFile::urlToLocalFileOrQrc(url).isEmpty() || !QDir::isRelativePath(QQmlFile::urlToLocalFileOrQrc(url)))); - +#else + // ### wasm asserts on urls like "qml/QtQuick.2.1/qmldir", + // which are relative urls we want to load over the network. +#endif LockHolder<QQmlTypeLoader> holder(this); QQmlQmldirData *qmldirData = m_qmldirCache.value(url); @@ -1848,6 +1862,52 @@ QString QQmlTypeLoader::absoluteFilePath(const QString &path) return absoluteFilePath; } +bool QQmlTypeLoader::fileExists(const QString &path, const QString &file) +{ + if (path.isEmpty()) + return false; + Q_ASSERT(path.endsWith(QLatin1Char('/'))); + if (path.at(0) == QLatin1Char(':')) { + // qrc resource + QFileInfo fileInfo(path + file); + return fileInfo.isFile(); + } else if (path.count() > 3 && path.at(3) == QLatin1Char(':') && + path.startsWith(QLatin1String("qrc"), Qt::CaseInsensitive)) { + // qrc resource url + QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path + file)); + return fileInfo.isFile(); + } +#if defined(Q_OS_ANDROID) + else if (path.count() > 7 && path.at(6) == QLatin1Char(':') && path.at(7) == QLatin1Char('/') && + path.startsWith(QLatin1String("assets"), Qt::CaseInsensitive)) { + // assets resource url + QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path + file)); + return fileInfo.isFile(); + } +#endif + + LockHolder<QQmlTypeLoader> holder(this); + if (!m_importDirCache.contains(path)) { + bool exists = QDir(path).exists(); + QCache<QString, bool> *entry = exists ? new QCache<QString, bool> : nullptr; + m_importDirCache.insert(path, entry); + } + QCache<QString, bool> *fileSet = m_importDirCache.object(path); + if (!fileSet) + return false; + + QString absoluteFilePath; + + bool *value = fileSet->object(file); + if (value) { + return *value; + } else { + bool exists = QFile::exists(path + file); + fileSet->insert(file, new bool(exists)); + return exists; + } +} + /*! Returns true if the path is a directory via a directory cache. Cache is diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 5d85773be3..031554b330 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -313,6 +313,7 @@ public: QQmlRefPointer<QQmlQmldirData> getQmldir(const QUrl &); QString absoluteFilePath(const QString &path); + bool fileExists(const QString &path, const QString &file); bool directoryExists(const QString &path); const QQmlTypeLoaderQmldirContent qmldirContent(const QString &filePath); diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index 78c9fe822b..d76344b613 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -138,11 +138,13 @@ QV8Engine::QV8Engine(QV4::ExecutionEngine *v4) , m_xmlHttpRequestData(nullptr) #endif { +#ifndef Q_OS_WASM // wasm does not have working simd QTBUG-63924 #ifdef Q_PROCESSOR_X86_32 if (!qCpuHasFeature(SSE2)) { qFatal("This program requires an X86 processor that supports SSE2 extension, at least a Pentium 4 or newer"); } #endif +#endif QML_MEMORY_SCOPE_STRING("QV8Engine::QV8Engine"); qMetaTypeId<QJSValue>(); diff --git a/src/qml/types/types.pri b/src/qml/types/types.pri index 492f408271..e0ff57a13e 100644 --- a/src/qml/types/types.pri +++ b/src/qml/types/types.pri @@ -5,7 +5,6 @@ SOURCES += \ $$PWD/qqmlmodelindexvaluetype.cpp \ $$PWD/qqmlobjectmodel.cpp \ $$PWD/qquickpackage.cpp \ - $$PWD/qquickworkerscript.cpp \ $$PWD/qqmlinstantiator.cpp \ $$PWD/qqmltableinstancemodel.cpp @@ -16,11 +15,17 @@ HEADERS += \ $$PWD/qqmlmodelindexvaluetype_p.h \ $$PWD/qqmlobjectmodel_p.h \ $$PWD/qquickpackage_p.h \ - $$PWD/qquickworkerscript_p.h \ $$PWD/qqmlinstantiator_p.h \ $$PWD/qqmlinstantiator_p_p.h \ $$PWD/qqmltableinstancemodel_p.h +qtConfig(thread) { + SOURCES += \ + $$PWD/qquickworkerscript.cpp + HEADERS += \ + $$PWD/qquickworkerscript_p.h +} + qtConfig(qml-list-model) { SOURCES += \ $$PWD/qqmllistmodel.cpp \ diff --git a/src/quick/configure.json b/src/quick/configure.json index 9ec3531ef4..9d7bafcb3b 100644 --- a/src/quick/configure.json +++ b/src/quick/configure.json @@ -129,7 +129,7 @@ "label": "Path support", "purpose": "Provides Path elements.", "section": "Qt Quick", - "condition": "features.quick-shadereffect", + "condition": "features.thread && features.quick-shadereffect", "output": [ "privateFeature" ] diff --git a/src/quick/doc/images/9BcAYDlpuT8.jpg b/src/quick/doc/images/9BcAYDlpuT8.jpg Binary files differnew file mode 100644 index 0000000000..0a69ab0034 --- /dev/null +++ b/src/quick/doc/images/9BcAYDlpuT8.jpg diff --git a/src/quick/doc/qtquick.qdocconf b/src/quick/doc/qtquick.qdocconf index ad5e47002d..34ec66bf1d 100644 --- a/src/quick/doc/qtquick.qdocconf +++ b/src/quick/doc/qtquick.qdocconf @@ -89,3 +89,7 @@ navigation.qmltypespage = "Qt Quick QML Types" # \svgcolor {#ffdead} macro.svgcolor.HTML = "<div style=\"padding:10px;color:#fff;background:\1;\"></div>" + +# youtube video thumbnails that show up in offline and online docs +HTML.extraimages += images/9BcAYDlpuT8.jpg +qhp.QtQuick.extraFiles += images/9BcAYDlpuT8.jpg diff --git a/src/quick/doc/snippets/qml/tableview/reusabledelegate.qml b/src/quick/doc/snippets/qml/tableview/reusabledelegate.qml new file mode 100644 index 0000000000..4a49e809cc --- /dev/null +++ b/src/quick/doc/snippets/qml/tableview/reusabledelegate.qml @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation 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 + +//![0] +Component { + id: tableViewDelegate + Rectangle { + implicitWidth: 100 + implicitHeight: 50 + + TableView.onPooled: rotationAnimation.pause() + TableView.onReused: rotationAnimation.resume() + + Rectangle { + id: rect + anchors.centerIn: parent + width: 40 + height: 5 + color: "green" + + RotationAnimation { + id: rotationAnimation + target: rect + duration: (Math.random() * 2000) + 200 + from: 0 + to: 359 + running: true + loops: Animation.Infinite + } + } + } +} +//![0] diff --git a/src/quick/doc/snippets/qml/tableview/tablemodel.cpp b/src/quick/doc/snippets/qml/tableview/tablemodel.cpp new file mode 100644 index 0000000000..ea9f76f131 --- /dev/null +++ b/src/quick/doc/snippets/qml/tableview/tablemodel.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** + ** + ** Copyright (C) 2018 The Qt Company Ltd. + ** Contact: https://www.qt.io/licensing/ + ** + ** This file is part of the documentation 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$ + ** + ****************************************************************************/ + +//![0] +#include <QGuiApplication> +#include <QQmlApplicationEngine> +#include <QAbstractTableModel> + +class TableModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + + int rowCount(const QModelIndex & = QModelIndex()) const override + { + return 200; + } + + int columnCount(const QModelIndex & = QModelIndex()) const override + { + return 200; + } + + QVariant data(const QModelIndex &index, int role) const override + { + switch (role) { + case Qt::DisplayRole: + return QString("%1, %2").arg(index.column()).arg(index.row()); + default: + break; + } + + return QVariant(); + } + + QHash<int, QByteArray> roleNames() const override + { + return { {Qt::DisplayRole, "display"} }; + } +}; + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + qmlRegisterType<TableModel>("TableModel", 0, 1, "TableModel"); + + QQmlApplicationEngine engine; + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + + return app.exec(); +} + +#include "main.moc" +//![0] diff --git a/src/quick/doc/snippets/qml/tableview/tablemodel.qml b/src/quick/doc/snippets/qml/tableview/tablemodel.qml new file mode 100644 index 0000000000..8a8ec94958 --- /dev/null +++ b/src/quick/doc/snippets/qml/tableview/tablemodel.qml @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation 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$ +** +****************************************************************************/ + +//![0] +import QtQuick 2.12 +import TableModel 0.1 + +TableView { + anchors.fill: parent + columnSpacing: 1 + rowSpacing: 1 + clip: true + + model: TableModel {} + + delegate: Rectangle { + implicitWidth: 100 + implicitHeight: 50 + Text { + text: display + } + } +} +//![0] diff --git a/src/quick/doc/snippets/qml/tableview/tableviewwithheader.qml b/src/quick/doc/snippets/qml/tableview/tableviewwithheader.qml new file mode 100644 index 0000000000..2214328ee7 --- /dev/null +++ b/src/quick/doc/snippets/qml/tableview/tableviewwithheader.qml @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation 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 + +//![0] +TableView { + id: tableView + + topMargin: header.implicitHeight + + Text { + id: header + text: "A table header" + } +} +//![0] diff --git a/src/quick/doc/snippets/qml/tableview/tableviewwithprovider.qml b/src/quick/doc/snippets/qml/tableview/tableviewwithprovider.qml new file mode 100644 index 0000000000..028b12ca6c --- /dev/null +++ b/src/quick/doc/snippets/qml/tableview/tableviewwithprovider.qml @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation 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 + +//![0] +TableView { + id: tableView + + property var columnWidths: [100, 50, 80, 150] + columnWidthProvider: function (column) { return columnWidths[column] } + + Timer { + running: true + interval: 2000 + onTriggered: { + tableView.columnWidths[2] = 150 + tableView.forceLayout(); + } + } +} +//![0] diff --git a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc index 2705ca5e34..e8265b92d2 100644 --- a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc +++ b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc @@ -41,9 +41,10 @@ QObjectList or a \l QAbstractItemModel. The first three are useful for exposing simpler datasets, while QAbstractItemModel provides a more flexible solution for more complex models. -For a video tutorial that takes you through the whole process of exposing a C++ -model to QML, see the -\l {https://youtu.be/9BcAYDlpuT8}{Using C++ Models in QML Tutorial}. +Here is a video tutorial that takes you through the whole process of exposing a C++ +model to QML: + +\youtube 9BcAYDlpuT8 \section2 QStringList-based Model diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h index 3623dcdf3a..5c95a12e9a 100644 --- a/src/quick/items/qquickevents_p_p.h +++ b/src/quick/items/qquickevents_p_p.h @@ -134,7 +134,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickMouseEvent : public QObject Q_PROPERTY(bool wasHeld READ wasHeld CONSTANT) Q_PROPERTY(bool isClick READ isClick CONSTANT) Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted) - Q_REVISION(11) Q_PROPERTY(int flags READ flags CONSTANT) + Q_PROPERTY(int flags READ flags CONSTANT REVISION 11) public: QQuickMouseEvent() diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp index 86a64cdeeb..ec74660d96 100644 --- a/src/quick/items/qquickrendercontrol.cpp +++ b/src/quick/items/qquickrendercontrol.cpp @@ -391,6 +391,7 @@ QImage QQuickRenderControl::grab() grabContent.setDevicePixelRatio(d->window->effectiveDevicePixelRatio()); } #endif +#if QT_CONFIG(thread) } else if (d->window->rendererInterface()->graphicsApi() == QSGRendererInterface::Software) { QQuickWindowPrivate *cd = QQuickWindowPrivate::get(d->window); cd->polishItems(); @@ -408,6 +409,7 @@ QImage QQuickRenderControl::grab() render(); softwareRenderer->setCurrentPaintDevice(prevDev); } +#endif } else { qWarning("QQuickRenderControl: grabs are not supported with the current Qt Quick backend"); } diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp index a1a5520239..2e594df8dd 100644 --- a/src/quick/items/qquicktableview.cpp +++ b/src/quick/items/qquicktableview.cpp @@ -51,6 +51,359 @@ #include <QtQuick/private/qquickflickable_p_p.h> #include <QtQuick/private/qquickitemviewfxitem_p_p.h> +/*! + \qmltype TableView + \instantiates QQuickTableView + \inqmlmodule QtQuick + \ingroup qtquick-views + \inherits Flickable + \brief Provides a table view of items provided by the model. + + A TableView has a \l model that defines the data to be displayed, and a + \l delegate that defines how the data should be displayed. + + TableView inherits \l Flickable. This means that while the model can have + any number of rows and columns, only a subsection of the table is usually + visible inside the viewport. As soon as you flick, new rows and columns + enter the viewport, while old ones exit and are removed from the viewport. + The rows and columns that move out are reused for building the rows and columns + that move into the viewport. As such, the TableView support models of any + size without affecting performance. + + A TableView displays data from models created from built-in QML types + such as ListModel and XmlListModel, which populates the first column only + in a TableView. To create models with multiple columns, create a model in + C++ that inherits QAbstractItemModel, and expose it to QML. + + \section1 Example Usage + + The following example shows how to create a model from C++ with multiple + columns: + + \snippet qml/tableview/tablemodel.cpp 0 + + And then how to use it from QML: + + \snippet qml/tableview/tablemodel.qml 0 + + \section1 Reusing items + + TableView recycles delegate items by default, instead of instantiating from + the \l delegate whenever new rows and columns are flicked into view. This + can give a huge performance boost, depending on the complexity of the + delegate. + + When an item is flicked out, it moves to the \e{reuse pool}, which is an + internal cache of unused items. When this happens, the \l TableView::pooled + signal is emitted to inform the item about it. Likewise, when the item is + moved back from the pool, the \l TableView::reused signal is emitted. + + Any item properties that come from the model are updated when the + item is reused. This includes \c index, \c row, and \c column, but also + any model roles. + + \note Avoid storing any state inside a delegate. If you do, reset it + manually on receiving the \l TableView::reused signal. + + If an item has timers or animations, consider pausing them on receiving + the \l TableView::pooled signal. That way you avoid using the CPU resources + for items that are not visible. Likewise, if an item has resources that + cannot be reused, they could be freed up. + + If you don't want to reuse items or if the \l delegate cannot support it, + you can set the \l reuseItems property to \c false. + + \note While an item is in the pool, it might still be alive and respond + to connected signals and bindings. + + The following example shows a delegate that animates a spinning rectangle. When + it is pooled, the animation is temporarily paused: + + \snippet qml/tableview/reusabledelegate.qml 0 + + \section1 Row heights and column widths + + When a new column is flicked into view, TableView will determine its width + by calling the \l columnWidthProvider function. TableView itself will never + store row height or column width, as it's designed to support large models + containing any number of rows and columns. Instead, it will ask the + application whenever it needs to know. + + TableView uses the largest \c implicitWidth among the items as the column + width, unless the \l columnWidthProvider property is explicitly set. Once + the column width is found, all other items in the same column are resized + to this width, even if new items that are flicked in later have larger + \c implicitWidth. Setting an explicit \l width on an item is ignored and + overwritten. + + \note The calculated width of a column is discarded when it is flicked out + of the viewport, and is recalculated if the column is flicked back in. The + calculation is always based on the items that are visible when the column + is flicked in. This means that it can end up different each time, depending + on which row you're at when the column enters. You should therefore have the + same \c implicitWidth for all items in a column, or set + \l columnWidthProvider. The same logic applies for the row height + calculation. + + If you change the values that a \l rowHeightProvider or a + \l columnWidthProvider return for rows and columns inside the viewport, you + must call \l forceLayout. This informs TableView that it needs to use the + provider functions again to recalculate and update the layout. + + \note The size of a row or column should be a whole number to avoid + sub-pixel alignment of items. + + The following example shows how to set a simple \c columnWidthProvider + together with a timer that modifies the values the function returns. When + the array is modified, \l forceLayout is called to let the changes + take effect: + + \snippet qml/tableview/tableviewwithprovider.qml 0 + + \section1 Overlays and underlays + + Tableview inherits \l Flickable. And when new items are instantiated from the + delegate, it will parent them to the \l{Flickable::}{contentItem} + with a \c z value equal to \c 1. You can add your own items inside the + Tableview, as child items of the Flickable. By controlling their \c z + value, you can make them be on top of or underneath the table items. + + Here is an example that shows how to add some text on top of the table, that + moves together with the table as you flick: + + \snippet qml/tableview/tableviewwithheader.qml 0 +*/ + +/*! + \qmlproperty int QtQuick::TableView::rows + + This property holds the number of rows in the table. This is + equal to the number of rows in the model. + + This property is read only. +*/ + +/*! + \qmlproperty int QtQuick::TableView::columns + + This property holds the number of columns in the table. This is + equal to the number of columns in the model. If the model is + a list, columns will be 1. + + This property is read only. +*/ + +/*! + \qmlproperty real QtQuick::TableView::rowSpacing + + This property holds the spacing between the rows. + + The default value is 0. +*/ + +/*! + \qmlproperty real QtQuick::TableView::columnSpacing + + This property holds the spacing between the columns. + + The default value is 0. +*/ + +/*! + \qmlproperty real QtQuick::TableView::topMargin + + This property holds the margin between the top of the table and + the top of the content view. + + The default value is 0. +*/ + +/*! + \qmlproperty real QtQuick::TableView::bottomMargin + + This property holds the margin between the bottom of the table and + the bottom of the content view. + + The default value is 0. +*/ + +/*! + \qmlproperty real QtQuick::TableView::leftMargin + + This property holds the margin between the left side of the table and + the left side of the content view. + + The default value is 0. +*/ + +/*! + \qmlproperty real QtQuick::TableView::rightMargin + + This property holds the margin between the right side of the table and + the right side of the content view. + + The default value is 0. +*/ + +/*! + \qmlproperty var QtQuick::TableView::rowHeightProvider + + This property can hold a function that returns the row height for each row + in the model. When assigned, it will be called whenever TableView needs to + know the height of a specific row. The function takes one argument, \c row, + for which the TableView needs to know the height. + + \note The height of a row must always be greater than \c 0. + + \sa columnWidthProvider, {Row heights and column widths} +*/ + +/*! + \qmlproperty var QtQuick::TableView::columnWidthProvider + + This property can hold a function that returns the column width for each + column in the model. When assigned, it is called whenever TableView needs + to know the width of a specific column. The function takes one argument, + \c column, for which the TableView needs to know the width. + + \note The width of a column must always be greater than \c 0. + + \sa rowHeightProvider, {Row heights and column widths} +*/ + +/*! + \qmlproperty model QtQuick::TableView::model + This property holds the model that provides data for the table. + + The model provides the set of data that is used to create the items + in the view. Models can be created directly in QML using \l ListModel, + \l XmlListModel or \l VisualItemModel, or provided by a custom C++ model + class. If it is a C++ model, it must be a subclass of \l QAbstractItemModel + or a simple list. + + \sa {qml-data-models}{Data Models} +*/ + +/*! + \qmlproperty Component QtQuick::TableView::delegate + + The delegate provides a template defining each cell item instantiated by the + view. The model index is exposed as an accessible \c index property. The same + applies to \c row and \c column. Properties of the model are also available + depending upon the type of \l {qml-data-models}{Data Model}. + + A delegate should specify its size using \l implicitWidth and \l implicitHeight. + The TableView lays out the items based on that information. Explicit \l width or + \l height settings are ignored and overwritten. + + \note Delegates are instantiated as needed and may be destroyed at any time. + They are also reused if the \l reuseItems property is set to \c true. You + should therefore avoid storing state information in the delegates. + + \sa {Row heights and column widths}, {Reusing items} +*/ + +/*! + \qmlproperty bool QtQuick::TableView::reuseItems + + This property holds whether or not items instantiated from the \l delegate + should be reused. If set to \c false, any currently pooled items + are destroyed. + + \sa {Reusing items}, TableView::pooled, TableView::reused +*/ + +/*! + \qmlproperty real QtQuick::TableView::contentWidth + + This property holds the width of the \l contentView, which is also + the width of the table (including margins). As a TableView cannot + always know the exact width of the table without loading all columns + in the model, the \c contentWidth is usually an estimated width based on + the columns it has seen so far. This estimate is recalculated whenever + new columns are flicked into view, which means that the content width + can change dynamically. + + If you know up front what the width of the table will be, assign a value + to \c contentWidth explicitly, to avoid unnecessary calculations and + updates to the TableView. + + \sa contentHeight +*/ + +/*! + \qmlproperty real QtQuick::TableView::contentHeight + + This property holds the height of the \l contentView, which is also + the height of the table (including margins). As a TableView cannot + always know the exact height of the table without loading all rows + in the model, the \c contentHeight is usually an estimated height + based on the rows it has seen so far. This estimate is recalculated + whenever new rows are flicked into view, which means that the content height + can change dynamically. + + If you know up front what the height of the table will be, assign a + value to \c contentHeight explicitly, to avoid unnecessary calculations and + updates to the TableView. + + \sa contentWidth +*/ + +/*! + \qmlmethod real QtQuick::TableView::forceLayout + + Responding to changes in the model are batched so that they are handled + only once per frame. This means the TableView delays showing any changes + while a script is being run. The same is also true when changing + properties such as \l rowSpacing or \l leftMargin. + + This method forces the TableView to immediately update the layout so + that any recent changes take effect. + + Calling this function re-evaluates the size and position of each visible + row and column. This is needed if the functions assigned to + \l rowHeightProvider or \l columnWidthProvider return different values than + what is already assigned. +*/ + +/*! + \qmlattachedproperty TableView QtQuick::TableView::view + + This attached property holds the view that manages the delegate instance. + It is attached to each instance of the delegate. +*/ + +/*! + \qmlattachedsignal QtQuick::TableView::pooled + + This signal is emitted after an item has been added to the reuse + pool. You can use it to pause ongoing timers or animations inside + the item, or free up resources that cannot be reused. + + This signal is emitted only if the \l reuseItems property is \c true. + + \sa {Reusing items}, reuseItems, reused +*/ + +/*! + \qmlattachedsignal QtQuick::TableView::reused + + This signal is emitted after an item has been reused. At this point, the + item has been taken out of the pool and placed inside the content view, + and the model properties such as index, row, and column have been updated. + + Other properties that are not provided by the model does not change when an item + is reused. You should avoid storing any state inside a delegate, but if you do, + manually reset that state on receiving this signal. + + This signal is emitted when the item is reused, and not the first time the + item is created. + + This signal is emitted only if the \l reuseItems property is \c true. + + \sa {Reusing items}, reuseItems, pooled +*/ + QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcTableViewDelegateLifecycle, "qt.quick.tableview.lifecycle") @@ -252,28 +605,30 @@ void QQuickTableViewPrivate::enforceTableAtOrigin() bool layoutNeeded = false; const qreal flickMargin = 50; - if (loadedTable.x() == 0 && loadedTableOuterRect.x() != tableMargins.left()) { + if (loadedTable.x() == 0 && loadedTableOuterRect.x() > tableMargins.left()) { // The table is at the beginning, but not at the edge of the // content view. So move the table to origo. loadedTableOuterRect.moveLeft(tableMargins.left()); layoutNeeded = true; - } else if (loadedTableOuterRect.x() < 0) { + } else if (loadedTableOuterRect.x() < tableMargins.left()) { // The table is outside the beginning of the content view. Move // the whole table inside, and make some room for flicking. - loadedTableOuterRect.moveLeft(tableMargins.left() + loadedTable.x() == 0 ? 0 : flickMargin); + loadedTableOuterRect.moveLeft(qFuzzyIsNull(tableMargins.left() + loadedTable.x()) ? 0 : flickMargin); layoutNeeded = true; } - if (loadedTable.y() == 0 && loadedTableOuterRect.y() != tableMargins.top()) { + if (loadedTable.y() == 0 && loadedTableOuterRect.y() > tableMargins.top()) { loadedTableOuterRect.moveTop(tableMargins.top()); layoutNeeded = true; - } else if (loadedTableOuterRect.y() < 0) { - loadedTableOuterRect.moveTop(tableMargins.top() + loadedTable.y() == 0 ? 0 : flickMargin); + } else if (loadedTableOuterRect.y() < tableMargins.top()) { + loadedTableOuterRect.moveTop(qFuzzyIsNull(tableMargins.top() + loadedTable.y()) ? 0 : flickMargin); layoutNeeded = true; } - if (layoutNeeded) + if (layoutNeeded) { + qCDebug(lcTableViewDelegateLifecycle); relayoutTableItems(); + } } void QQuickTableViewPrivate::syncLoadedTableRectFromLoadedTable() diff --git a/src/quick/scenegraph/adaptations/adaptations.pri b/src/quick/scenegraph/adaptations/adaptations.pri index 40fa739e15..bfd7095718 100644 --- a/src/quick/scenegraph/adaptations/adaptations.pri +++ b/src/quick/scenegraph/adaptations/adaptations.pri @@ -1 +1 @@ -include(software/software.pri) +qtConfig(thread): include(software/software.pri) diff --git a/src/quick/scenegraph/qsgcontextplugin.cpp b/src/quick/scenegraph/qsgcontextplugin.cpp index 66add51c55..4f8b1cf332 100644 --- a/src/quick/scenegraph/qsgcontextplugin.cpp +++ b/src/quick/scenegraph/qsgcontextplugin.cpp @@ -89,8 +89,10 @@ struct QSGAdaptationBackendData QSGAdaptationBackendData::QSGAdaptationBackendData() : flags(nullptr) { +#if QT_CONFIG(thread) // Fill in the table with the built-in adaptations. builtIns.append(new QSGSoftwareAdaptation); +#endif } QSGAdaptationBackendData::~QSGAdaptationBackendData() diff --git a/src/quick/scenegraph/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp index 22e97a2dc9..73b79c6300 100644 --- a/src/quick/scenegraph/qsgdefaultrendercontext.cpp +++ b/src/quick/scenegraph/qsgdefaultrendercontext.cpp @@ -325,7 +325,8 @@ bool QSGDefaultRenderContext::separateIndexBuffer() const // lifetime. An attempt to bind a buffer object to the other // target will generate an INVALID_OPERATION error, and the // current binding will remain untouched. - static const bool isWebGL = qGuiApp->platformName().compare(QLatin1String("webgl")) == 0; + static const bool isWebGL = (qGuiApp->platformName().compare(QLatin1String("webgl")) == 0 + || qGuiApp->platformName().compare(QLatin1String("wasm")) == 0); return isWebGL; } diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index 2eaed497ef..79bfe95e90 100644 --- a/src/quick/scenegraph/qsgrenderloop.cpp +++ b/src/quick/scenegraph/qsgrenderloop.cpp @@ -221,10 +221,12 @@ QSGRenderLoop *QSGRenderLoop::instance() } switch (loopType) { +#if QT_CONFIG(thread) case ThreadedRenderLoop: qCDebug(QSG_LOG_INFO, "threaded render loop"); s_instance = new QSGThreadedRenderLoop(); break; +#endif case WindowsRenderLoop: qCDebug(QSG_LOG_INFO, "windows render loop"); s_instance = new QSGWindowsRenderLoop(); diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri index f08e8b7863..ddd7fb7f4c 100644 --- a/src/quick/scenegraph/scenegraph.pri +++ b/src/quick/scenegraph/scenegraph.pri @@ -115,7 +115,6 @@ qtConfig(opengl(es1|es2)?) { $$PWD/util/qsgdefaultimagenode.cpp \ $$PWD/util/qsgdefaultninepatchnode.cpp \ $$PWD/qsgdefaultlayer.cpp \ - $$PWD/qsgthreadedrenderloop.cpp \ $$PWD/qsgwindowsrenderloop.cpp HEADERS += \ $$PWD/qsgdefaultglyphnode_p.h \ @@ -132,9 +131,15 @@ qtConfig(opengl(es1|es2)?) { $$PWD/util/qsgdefaultimagenode_p.h \ $$PWD/util/qsgdefaultninepatchnode_p.h \ $$PWD/qsgdefaultlayer_p.h \ - $$PWD/qsgthreadedrenderloop_p.h \ $$PWD/qsgwindowsrenderloop_p.h + qtConfig(thread) { + SOURCES += \ + $$PWD/qsgthreadedrenderloop.cpp + HEADERS += \ + $$PWD/qsgthreadedrenderloop_p.h + } + qtConfig(quick-sprite) { SOURCES += \ $$PWD/qsgdefaultspritenode.cpp diff --git a/src/quick/scenegraph/util/qsgtexturereader.cpp b/src/quick/scenegraph/util/qsgtexturereader.cpp index 27ba119f63..5e12ca4035 100644 --- a/src/quick/scenegraph/util/qsgtexturereader.cpp +++ b/src/quick/scenegraph/util/qsgtexturereader.cpp @@ -38,9 +38,12 @@ ****************************************************************************/ #include "qsgtexturereader_p.h" -#include <private/qsgcompressedtexture_p.h> #include <private/qtexturefilereader_p.h> +#if QT_CONFIG(opengl) +#include <private/qsgcompressedtexture_p.h> +#endif + QT_BEGIN_NAMESPACE QSGTextureReader::QSGTextureReader(QIODevice *device, const QString &fileName) diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index a098c94670..8646dd32e3 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -297,6 +297,7 @@ void QQuickWidgetPrivate::render(bool needsSync) QOpenGLContextPrivate::get(context)->defaultFboRedirect = 0; #endif } else { +#if QT_CONFIG(thread) //Software Renderer if (needsSync) { renderControl->polishItems(); @@ -315,6 +316,7 @@ void QQuickWidgetPrivate::render(bool needsSync) updateRegion += softwareRenderer->flushRegion(); } +#endif } } diff --git a/src/src.pro b/src/src.pro index 2dc6fc2758..ba96bd09a1 100644 --- a/src/src.pro +++ b/src/src.pro @@ -9,7 +9,9 @@ SUBDIRS += \ qtHaveModule(gui):qtConfig(qml-animation) { SUBDIRS += \ quick \ - quickshapes + + qtConfig(thread): \ + SUBDIRS += quickshapes qtConfig(testlib): \ SUBDIRS += qmltest diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations index bcb6729ab6..fe2e9835e1 100644 --- a/tests/auto/qml/ecmascripttests/TestExpectations +++ b/tests/auto/qml/ecmascripttests/TestExpectations @@ -112,8 +112,6 @@ built-ins/Array/prototype/unshift/length-near-integer-limit.js fails built-ins/Array/prototype/unshift/throws-if-integer-limit-exceeded.js fails built-ins/ArrayBuffer/data-allocation-after-object-creation.js fails built-ins/ArrayBuffer/proto-from-ctor-realm.js fails -built-ins/ArrayBuffer/prototype-from-newtarget.js fails -built-ins/ArrayBuffer/prototype/slice/nonconstructor.js fails built-ins/ArrayIteratorPrototype/next/detach-typedarray-in-progress.js fails built-ins/AsyncFunction/AsyncFunction-construct.js fails built-ins/AsyncFunction/AsyncFunction-is-extensible.js fails @@ -148,7 +146,6 @@ built-ins/Atomics/wake/wake-one.js fails built-ins/Atomics/wake/wake-two.js fails built-ins/Atomics/wake/wake-zero.js fails built-ins/Boolean/proto-from-ctor-realm.js fails -built-ins/DataView/custom-proto-access-throws.js fails built-ins/DataView/custom-proto-if-object-is-used.js fails built-ins/DataView/proto-from-ctor-realm.js fails built-ins/Date/UTC/infinity-make-day.js fails @@ -177,9 +174,7 @@ built-ins/Function/internals/Construct/base-ctor-revoked-proxy-realm.js fails built-ins/Function/internals/Construct/base-ctor-revoked-proxy.js fails built-ins/Function/internals/Construct/derived-return-val-realm.js fails built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js fails -built-ins/Function/internals/Construct/derived-this-uninitialized.js fails built-ins/Function/proto-from-ctor-realm.js fails -built-ins/Function/prototype/Symbol.hasInstance/this-val-poisoned-prototype.js fails built-ins/Function/prototype/bind/BoundFunction_restricted-properties.js fails built-ins/Function/prototype/bind/get-fn-realm.js fails built-ins/Function/prototype/bind/instance-name-chained.js fails @@ -231,7 +226,6 @@ built-ins/Object/getOwnPropertyDescriptors/symbols-included.js fails built-ins/Object/keys/proxy-keys.js fails built-ins/Object/proto-from-ctor.js fails built-ins/Object/prototype/toLocaleString/primitive_this_value_getter.js strictFails -built-ins/Object/prototype/toString/no-prototype-property.js fails built-ins/Object/prototype/toString/proxy-array.js fails built-ins/Object/prototype/toString/proxy-function.js fails built-ins/Object/prototype/valueOf/S15.2.4.4_A14.js fails @@ -427,9 +421,7 @@ built-ins/Proxy/ownKeys/return-not-list-object-throws-realm.js fails built-ins/Proxy/ownKeys/trap-is-not-callable-realm.js fails built-ins/Proxy/ownKeys/trap-is-undefined.js fails built-ins/Proxy/preventExtensions/trap-is-not-callable-realm.js fails -built-ins/Proxy/proxy-no-prototype.js fails built-ins/Proxy/revocable/revocation-function-name.js fails -built-ins/Proxy/revocable/revocation-function-nonconstructor.js fails built-ins/Proxy/set/trap-is-not-callable-realm.js fails built-ins/Proxy/setPrototypeOf/trap-is-not-callable-realm.js fails built-ins/RegExp/S15.10.2.12_A2_T1.js fails @@ -453,11 +445,9 @@ built-ins/RegExp/unicode_restricted_quantifiable_assertion.js fails built-ins/RegExp/u180e.js fails built-ins/Set/proto-from-ctor-realm.js fails built-ins/Set/prototype/forEach/iterates-values-revisits-after-delete-re-add.js fails -built-ins/Set/prototype/forEach/this-arg-explicit-cannot-override-lexical-this-arrow.js fails built-ins/SharedArrayBuffer/data-allocation-after-object-creation.js fails built-ins/SharedArrayBuffer/proto-from-ctor-realm.js fails built-ins/SharedArrayBuffer/prototype-from-newtarget.js fails -built-ins/SharedArrayBuffer/prototype/slice/nonconstructor.js fails built-ins/String/proto-from-ctor-realm.js fails built-ins/String/prototype/endsWith/return-abrupt-from-searchstring-regexp-test.js fails built-ins/String/prototype/includes/return-abrupt-from-searchstring-regexp-test.js fails @@ -520,36 +510,24 @@ built-ins/TypedArray/prototype/sort/return-same-instance.js fails built-ins/TypedArray/prototype/sort/sortcompare-with-no-tostring.js fails built-ins/TypedArray/prototype/sort/sorted-values-nan.js fails built-ins/TypedArray/prototype/sort/sorted-values.js fails -built-ins/TypedArrays/ctors/buffer-arg/custom-proto-access-throws.js fails built-ins/TypedArrays/ctors/buffer-arg/defined-negative-length.js fails built-ins/TypedArrays/ctors/buffer-arg/proto-from-ctor-realm.js fails -built-ins/TypedArrays/ctors/buffer-arg/use-custom-proto-if-object.js fails -built-ins/TypedArrays/ctors/length-arg/custom-proto-access-throws.js fails built-ins/TypedArrays/ctors/length-arg/proto-from-ctor-realm.js fails -built-ins/TypedArrays/ctors/length-arg/use-custom-proto-if-object.js fails -built-ins/TypedArrays/ctors/no-args/custom-proto-access-throws.js fails built-ins/TypedArrays/ctors/no-args/proto-from-ctor-realm.js fails -built-ins/TypedArrays/ctors/no-args/use-custom-proto-if-object.js fails built-ins/TypedArrays/ctors/object-arg/as-generator-iterable-returns.js fails -built-ins/TypedArrays/ctors/object-arg/custom-proto-access-throws.js fails built-ins/TypedArrays/ctors/object-arg/iterator-not-callable-throws.js fails built-ins/TypedArrays/ctors/object-arg/proto-from-ctor-realm.js fails -built-ins/TypedArrays/ctors/object-arg/use-custom-proto-if-object.js fails -built-ins/TypedArrays/ctors/typedarray-arg/custom-proto-access-throws.js fails built-ins/TypedArrays/ctors/typedarray-arg/detached-when-species-retrieved-different-type.js fails built-ins/TypedArrays/ctors/typedarray-arg/detached-when-species-retrieved-same-type.js fails built-ins/TypedArrays/ctors/typedarray-arg/other-ctor-buffer-ctor-custom-species-proto-from-ctor-realm.js fails built-ins/TypedArrays/ctors/typedarray-arg/other-ctor-buffer-ctor-custom-species.js fails built-ins/TypedArrays/ctors/typedarray-arg/other-ctor-buffer-ctor-not-object-throws.js fails built-ins/TypedArrays/ctors/typedarray-arg/other-ctor-buffer-ctor-species-not-ctor-throws.js fails -built-ins/TypedArrays/ctors/typedarray-arg/other-ctor-buffer-ctor-species-prototype-throws.js fails built-ins/TypedArrays/ctors/typedarray-arg/proto-from-ctor-realm.js fails built-ins/TypedArrays/ctors/typedarray-arg/same-ctor-buffer-ctor-species-custom-proto-from-ctor-realm.js fails built-ins/TypedArrays/ctors/typedarray-arg/same-ctor-buffer-ctor-species-custom.js fails built-ins/TypedArrays/ctors/typedarray-arg/same-ctor-buffer-ctor-species-not-ctor.js fails -built-ins/TypedArrays/ctors/typedarray-arg/same-ctor-buffer-ctor-species-prototype-throws.js fails built-ins/TypedArrays/ctors/typedarray-arg/same-ctor-buffer-ctor-value-not-obj-throws.js fails -built-ins/TypedArrays/ctors/typedarray-arg/use-custom-proto-if-object.js fails built-ins/TypedArrays/from/arylk-get-length-error.js fails built-ins/TypedArrays/from/arylk-to-length-error.js fails built-ins/TypedArrays/from/custom-ctor-returns-other-instance.js fails @@ -573,45 +551,21 @@ built-ins/TypedArrays/from/new-instance-with-mapfn.js fails built-ins/TypedArrays/from/new-instance-without-mapfn.js fails built-ins/TypedArrays/from/property-abrupt-completion.js fails built-ins/TypedArrays/from/set-value-abrupt-completion.js fails -built-ins/TypedArrays/internals/DefineOwnProperty/conversion-operation-consistent-nan.js fails -built-ins/TypedArrays/internals/DefineOwnProperty/conversion-operation.js fails built-ins/TypedArrays/internals/DefineOwnProperty/detached-buffer-realm.js fails -built-ins/TypedArrays/internals/DefineOwnProperty/detached-buffer.js fails -built-ins/TypedArrays/internals/DefineOwnProperty/key-is-greater-than-last-index.js fails -built-ins/TypedArrays/internals/DefineOwnProperty/key-is-lower-than-zero.js fails -built-ins/TypedArrays/internals/DefineOwnProperty/key-is-minus-zero.js fails -built-ins/TypedArrays/internals/DefineOwnProperty/key-is-not-integer.js fails -built-ins/TypedArrays/internals/DefineOwnProperty/key-is-numericindex-accessor-desc.js fails -built-ins/TypedArrays/internals/DefineOwnProperty/key-is-numericindex-desc-configurable.js fails -built-ins/TypedArrays/internals/DefineOwnProperty/key-is-numericindex-desc-not-enumerable.js fails -built-ins/TypedArrays/internals/DefineOwnProperty/key-is-numericindex-desc-not-writable.js fails built-ins/TypedArrays/internals/DefineOwnProperty/key-is-numericindex.js fails -built-ins/TypedArrays/internals/DefineOwnProperty/set-value.js fails -built-ins/TypedArrays/internals/DefineOwnProperty/tonumber-value-detached-buffer.js fails built-ins/TypedArrays/internals/Get/detached-buffer-realm.js fails -built-ins/TypedArrays/internals/Get/detached-buffer.js fails -built-ins/TypedArrays/internals/Get/infinity-detached-buffer.js fails built-ins/TypedArrays/internals/Get/key-is-not-integer.js fails built-ins/TypedArrays/internals/Get/key-is-not-minus-zero.js fails built-ins/TypedArrays/internals/Get/key-is-out-of-bounds.js fails built-ins/TypedArrays/internals/GetOwnProperty/detached-buffer-realm.js fails -built-ins/TypedArrays/internals/GetOwnProperty/detached-buffer.js fails built-ins/TypedArrays/internals/GetOwnProperty/enumerate-detached-buffer.js fails built-ins/TypedArrays/internals/GetOwnProperty/index-prop-desc.js fails built-ins/TypedArrays/internals/HasProperty/detached-buffer-realm.js fails -built-ins/TypedArrays/internals/HasProperty/detached-buffer.js fails -built-ins/TypedArrays/internals/HasProperty/infinity-with-detached-buffer.js sloppyFails -built-ins/TypedArrays/internals/HasProperty/key-is-lower-than-zero.js fails -built-ins/TypedArrays/internals/HasProperty/key-is-minus-zero.js fails -built-ins/TypedArrays/internals/HasProperty/key-is-not-integer.js fails built-ins/TypedArrays/internals/OwnPropertyKeys/integer-indexes-and-string-and-symbol-keys-.js fails built-ins/TypedArrays/internals/OwnPropertyKeys/integer-indexes-and-string-keys.js fails built-ins/TypedArrays/internals/OwnPropertyKeys/integer-indexes.js fails built-ins/TypedArrays/internals/Set/detached-buffer-realm.js fails built-ins/TypedArrays/internals/Set/detached-buffer.js fails -built-ins/TypedArrays/internals/Set/key-is-minus-zero.js fails -built-ins/TypedArrays/internals/Set/key-is-not-integer.js fails -built-ins/TypedArrays/internals/Set/key-is-out-of-bounds.js fails built-ins/TypedArrays/internals/Set/tonumber-value-throws.js strictFails built-ins/WeakMap/proto-from-ctor-realm.js fails built-ins/WeakSet/proto-from-ctor-realm.js fails @@ -661,18 +615,12 @@ language/eval-code/indirect/var-env-global-lex-non-strict.js fails language/eval-code/indirect/var-env-var-init-global-exstng.js strictFails language/eval-code/indirect/var-env-var-init-global-new.js strictFails language/eval-code/indirect/var-env-var-non-strict.js strictFails -language/expressions/arrow-function/cannot-override-this-with-thisArg.js fails language/expressions/arrow-function/dflt-params-ref-later.js fails language/expressions/arrow-function/dflt-params-ref-self.js fails -language/expressions/arrow-function/lexical-arguments.js fails language/expressions/arrow-function/lexical-new.target-closure-returned.js fails language/expressions/arrow-function/lexical-new.target.js fails language/expressions/arrow-function/lexical-super-call-from-within-constructor.js fails -language/expressions/arrow-function/lexical-super-property-from-within-constructor.js fails -language/expressions/arrow-function/lexical-super-property.js fails language/expressions/arrow-function/lexical-supercall-from-immediately-invoked-arrow.js fails -language/expressions/arrow-function/lexical-this.js fails -language/expressions/arrow-function/prototype-rules.js fails language/expressions/arrow-function/scope-body-lex-distinct.js sloppyFails language/expressions/arrow-function/scope-param-elem-var-close.js sloppyFails language/expressions/arrow-function/scope-param-elem-var-open.js sloppyFails @@ -887,7 +835,6 @@ language/expressions/object/method-definition/gen-yield-identifier-non-strict.js language/expressions/object/method-definition/meth-dflt-params-ref-later.js fails language/expressions/object/method-definition/meth-dflt-params-ref-self.js fails language/expressions/object/method-definition/name-invoke-ctor.js fails -language/expressions/object/method-definition/name-prototype-prop.js fails language/expressions/object/method-definition/object-method-returns-promise.js fails language/expressions/object/method-definition/yield-as-function-expression-binding-identifier.js sloppyFails language/expressions/object/method-definition/yield-as-identifier-in-nested-function.js sloppyFails @@ -934,10 +881,6 @@ language/expressions/prefix-increment/S11.4.4_A5_T3.js sloppyFails language/expressions/prefix-increment/S11.4.4_A5_T4.js sloppyFails language/expressions/prefix-increment/S11.4.4_A5_T5.js fails language/expressions/prefix-increment/S11.4.4_A6_T3.js fails -language/expressions/super/prop-dot-cls-val-from-arrow.js fails -language/expressions/super/prop-dot-obj-val-from-arrow.js fails -language/expressions/super/prop-expr-cls-val-from-arrow.js fails -language/expressions/super/prop-expr-obj-val-from-arrow.js fails language/expressions/super/realm.js fails language/expressions/tagged-template/cache-different-functions-same-site.js fails language/expressions/tagged-template/cache-eval-inner-function.js fails @@ -1027,20 +970,13 @@ language/statements/block/tco-stmt-list.js strictFails language/statements/block/tco-stmt.js strictFails language/statements/class/constructor-inferred-observable-iteration.js fails language/statements/class/cptn-decl.js fails -language/statements/class/definition/accessors.js fails language/statements/class/definition/class-method-returns-promise.js fails -language/statements/class/definition/getters-prop-desc.js fails language/statements/class/definition/getters-restricted-ids.js fails -language/statements/class/definition/invalid-extends.js strictFails language/statements/class/definition/methods-gen-yield-as-literal-property-name.js fails language/statements/class/definition/methods-gen-yield-as-property-name.js fails language/statements/class/definition/methods-gen-yield-star-before-newline.js fails language/statements/class/definition/methods-named-eval-arguments.js fails -language/statements/class/definition/methods.js fails -language/statements/class/definition/numeric-property-names.js fails -language/statements/class/definition/prototype-getter.js fails language/statements/class/definition/prototype-property.js fails -language/statements/class/definition/prototype-setter.js fails language/statements/class/definition/setters-prop-desc.js fails language/statements/class/definition/setters-restricted-ids.js fails language/statements/class/definition/this-access-restriction-2.js fails @@ -1061,34 +997,8 @@ language/statements/class/scope-static-gen-meth-paramsbody-var-open.js fails language/statements/class/scope-static-meth-paramsbody-var-open.js fails language/statements/class/scope-static-setter-paramsbody-var-open.js fails language/statements/class/subclass/bound-function.js fails -language/statements/class/subclass/builtin-objects/Array/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/ArrayBuffer/regular-subclassing.js fails -language/statements/class/subclass/builtin-objects/ArrayBuffer/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/Boolean/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/DataView/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/Date/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/Error/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/Function/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/GeneratorFunction/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/Map/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/NativeError/EvalError-super.js fails -language/statements/class/subclass/builtin-objects/NativeError/RangeError-super.js fails -language/statements/class/subclass/builtin-objects/NativeError/ReferenceError-super.js fails -language/statements/class/subclass/builtin-objects/NativeError/SyntaxError-super.js fails -language/statements/class/subclass/builtin-objects/NativeError/TypeError-super.js fails -language/statements/class/subclass/builtin-objects/NativeError/URIError-super.js fails -language/statements/class/subclass/builtin-objects/Number/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/Object/constructor-return-undefined-throws.js fails language/statements/class/subclass/builtin-objects/Promise/regular-subclassing.js fails language/statements/class/subclass/builtin-objects/Promise/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/RegExp/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/Set/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/String/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/TypedArray/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/WeakMap/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/WeakSet/super-must-be-called.js fails -language/statements/class/subclass/builtins.js fails -language/statements/class/subclass/class-definition-null-proto-this.js fails language/statements/class/subclass/default-constructor-spread-override.js fails language/statements/do-while/tco-body.js strictFails language/statements/for-in/head-lhs-let.js sloppyFails diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 99306d8d15..cf3eecff6d 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -1600,7 +1600,7 @@ void tst_qqmlecmascript::aliasPropertyReset() // test that a manual write (of undefined) to a non-resettable property fails properly QUrl url = testFileUrl("aliasreset/aliasPropertyReset.error.1.qml"); - QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int"); + QString warning1 = url.toString() + QLatin1String(": Error: Cannot assign [undefined] to int"); QQmlComponent e1(&engine, url); object = e1.create(); QVERIFY(object != nullptr); diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp index e5b06051a5..e25a7b72bb 100644 --- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp +++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp @@ -717,16 +717,28 @@ void tst_QQuickTableView::checkLayoutOfEqualSizedDelegateItems() void tst_QQuickTableView::checkTableMargins_data() { QTest::addColumn<QVariant>("model"); - QTest::addColumn<QSize>("tableSize"); QTest::addColumn<QSizeF>("spacing"); QTest::addColumn<QMarginsF>("margins"); - QTest::newRow("QAIM 1x1 1,1 0000") << TestModelAsVariant(1, 1) << QSize(1, 1) << QSizeF(1, 1) << QMarginsF(0, 0, 0, 0); - QTest::newRow("QAIM 4x4 1,1 0000") << TestModelAsVariant(4, 4) << QSize(4, 4) << QSizeF(1, 1) << QMarginsF(0, 0, 0, 0); - QTest::newRow("QAIM 1x1 1,1 5555") << TestModelAsVariant(1, 1) << QSize(1, 1) << QSizeF(1, 1) << QMarginsF(5, 5, 5, 5); - QTest::newRow("QAIM 4x4 0,0 3333") << TestModelAsVariant(4, 4) << QSize(4, 4) << QSizeF(0, 0) << QMarginsF(3, 3, 3, 3); - QTest::newRow("QAIM 4x4 2,2 1234") << TestModelAsVariant(4, 4) << QSize(4, 4) << QSizeF(2, 2) << QMarginsF(1, 2, 3, 4); - QTest::newRow("QAIM 1x1 0,0 3210") << TestModelAsVariant(1, 1) << QSize(1, 1) << QSizeF(0, 0) << QMarginsF(3, 2, 1, 0); + QTest::newRow("QAIM single") << TestModelAsVariant(1, 1) << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0); + QTest::newRow("QAIM single, 1,1, no margins") << TestModelAsVariant(1, 1) << QSizeF(1, 1) << QMarginsF(0, 0, 0, 0); + QTest::newRow("QAIM single, no spacing, 1111") << TestModelAsVariant(1, 1) << QSizeF(0, 0) << QMarginsF(1, 1, 1, 1); + + QTest::newRow("QAIM 4x4") << TestModelAsVariant(4, 4) << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0); + QTest::newRow("QAIM 4x4, 1,1, no margins") << TestModelAsVariant(4, 4) << QSizeF(1, 1) << QMarginsF(0, 0, 0, 0); + QTest::newRow("QAIM 4x4, no spacing, 1111") << TestModelAsVariant(1, 1) << QSizeF(0, 0) << QMarginsF(1, 1, 1, 1); + + QTest::newRow("QAIM 1,1 0000") << TestModelAsVariant(20, 20) << QSizeF(1, 1) << QMarginsF(0, 0, 0, 0); + QTest::newRow("QAIM 1,1 5555") << TestModelAsVariant(20, 20) << QSizeF(1, 1) << QMarginsF(5, 5, 5, 5); + QTest::newRow("QAIM 0,0 3333") << TestModelAsVariant(20, 20) << QSizeF(0, 0) << QMarginsF(3, 3, 3, 3); + QTest::newRow("QAIM 2,2 1234") << TestModelAsVariant(20, 20) << QSizeF(2, 2) << QMarginsF(1, 2, 3, 4); + QTest::newRow("QAIM 0,0 3210") << TestModelAsVariant(20, 20) << QSizeF(0, 0) << QMarginsF(3, 2, 1, 0); + + QTest::newRow("QAIM 0,0 negative left margin") << TestModelAsVariant(20, 20) << QSizeF(0, 0) << QMarginsF(-10, 0, 0, 0); + QTest::newRow("QAIM 0,0 negative top margin") << TestModelAsVariant(20, 20) << QSizeF(0, 0) << QMarginsF(0, -10, 0, 0); + QTest::newRow("QAIM 0,0 negative right margin") << TestModelAsVariant(20, 20) << QSizeF(0, 0) << QMarginsF(0, 0, -10, 0); + QTest::newRow("QAIM 0,0 negative bottom margin") << TestModelAsVariant(20, 20) << QSizeF(0, 0) << QMarginsF(0, 0, 0, -10); + QTest::newRow("QAIM 0,0 all margins negative") << TestModelAsVariant(20, 20) << QSizeF(0, 0) << QMarginsF(-10, -10, -10, -10); } void tst_QQuickTableView::checkTableMargins() @@ -734,7 +746,6 @@ void tst_QQuickTableView::checkTableMargins() // Check that the space between the content view and // the items matches the margins we set on the tableview. QFETCH(QVariant, model); - QFETCH(QSize, tableSize); QFETCH(QSizeF, spacing); QFETCH(QMarginsF, margins); LOAD_TABLEVIEW("plaintableview.qml"); @@ -749,19 +760,22 @@ void tst_QQuickTableView::checkTableMargins() WAIT_UNTIL_POLISHED; - QCOMPARE(tableViewPrivate->loadedTable.size(), tableSize); - - auto const topLeftFxItem = tableViewPrivate->loadedTableItem(QPoint(0, 0)); - auto const bottomRightFxItem = tableViewPrivate->loadedTableItem(tableViewPrivate->loadedTable.bottomRight()); - auto const topLeftItem = topLeftFxItem->item; - auto const bottomRightItem = bottomRightFxItem->item; - + // Check left-, and top margins + auto const topLeftItem = tableViewPrivate->loadedTableItem(QPoint(0, 0))->item; qreal leftSpace = topLeftItem->x(); qreal topSpace = topLeftItem->y(); - qreal rightSpace = tableView->contentWidth() - (bottomRightItem->x() + bottomRightItem->width()); - qreal bottomSpace = tableView->contentHeight() - (bottomRightItem->y() + bottomRightItem->height()); QCOMPARE(leftSpace, margins.left()); QCOMPARE(topSpace, margins.top()); + + // Flick the table to the end... + tableView->setContentX(tableView->contentWidth() - tableView->width()); + tableView->setContentY(tableView->contentHeight() - tableView->height()); + const QPoint bottomRightCell = tableViewPrivate->loadedTable.bottomRight(); + auto const bottomRightItem = tableViewPrivate->loadedTableItem(bottomRightCell)->item; + + // ...and check the right-, and bottom margins + qreal rightSpace = tableView->contentWidth() - (bottomRightItem->x() + bottomRightItem->width()); + qreal bottomSpace = tableView->contentHeight() - (bottomRightItem->y() + bottomRightItem->height()); QCOMPARE(rightSpace, margins.right()); QCOMPARE(bottomSpace, margins.bottom()); } diff --git a/tools/tools.pro b/tools/tools.pro index 779b656198..ef4872d1a1 100644 --- a/tools/tools.pro +++ b/tools/tools.pro @@ -9,7 +9,7 @@ qtConfig(qml-devtools) { qtConfig(commandlineparser):qtConfig(xmlstreamwriter): SUBDIRS += qmlcachegen } -!android|android_app { +qtConfig(thread):!android|android_app { SUBDIRS += \ qml |