diff options
Diffstat (limited to 'src')
46 files changed, 450 insertions, 214 deletions
diff --git a/src/imports/testlib/quicktestevent.cpp b/src/imports/testlib/quicktestevent.cpp index f2d7f93d26..59b7f15946 100644 --- a/src/imports/testlib/quicktestevent.cpp +++ b/src/imports/testlib/quicktestevent.cpp @@ -231,8 +231,10 @@ namespace QtQuickTest QTEST_ASSERT(item); if (delay == -1 || delay < QTest::defaultMouseDelay()) delay = QTest::defaultMouseDelay(); - if (delay > 0) + if (delay > 0) { QTest::qWait(delay); + lastMouseTimestamp += delay; + } QPoint pos; QQuickItem *sgitem = qobject_cast<QQuickItem *>(item); @@ -245,6 +247,7 @@ namespace QtQuickTest stateKey &= static_cast<unsigned int>(Qt::KeyboardModifierMask); QWheelEvent we(pos, window->mapToGlobal(pos), QPoint(0, 0), QPoint(xDelta, yDelta), buttons, stateKey, Qt::NoScrollPhase, false); + we.setTimestamp(++lastMouseTimestamp); QSpontaneKeyEvent::setSpontaneous(&we); // hmmmm if (!qApp->notify(window, &we)) diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp index f3c12bce3f..e15771531a 100644 --- a/src/qml/animations/qabstractanimationjob.cpp +++ b/src/qml/animations/qabstractanimationjob.cpp @@ -65,6 +65,30 @@ QQmlAnimationTimer::QQmlAnimationTimer() : { } +void QQmlAnimationTimer::unsetJobTimer(QAbstractAnimationJob *animation) +{ + if (!animation) + return; + if (animation->m_timer == this) + animation->m_timer = nullptr; + + if (animation->isGroup()) { + QAnimationGroupJob *group = static_cast<QAnimationGroupJob *>(animation); + for (auto *child = group->firstChild(); child; child = child->nextSibling()) + unsetJobTimer(child); + } +} + +QQmlAnimationTimer::~QQmlAnimationTimer() +{ + for (const auto &animation : qAsConst(animations)) + unsetJobTimer(animation); + for (const auto &animation : qAsConst(animationsToStart)) + unsetJobTimer(animation); + for (const auto &animation : qAsConst(runningPauseAnimations)) + unsetJobTimer(animation); +} + QQmlAnimationTimer *QQmlAnimationTimer::instance(bool create) { QQmlAnimationTimer *inst; @@ -216,6 +240,7 @@ void QQmlAnimationTimer::registerRunningAnimation(QAbstractAnimationJob *animati void QQmlAnimationTimer::unregisterRunningAnimation(QAbstractAnimationJob *animation) { + unsetJobTimer(animation); if (animation->userControlDisabled()) return; @@ -282,8 +307,10 @@ QAbstractAnimationJob::~QAbstractAnimationJob() Q_ASSERT(m_state == Stopped); if (oldState == Running) { - Q_ASSERT(QQmlAnimationTimer::instance() == m_timer); - m_timer->unregisterAnimation(this); + if (m_timer) { + Q_ASSERT(QQmlAnimationTimer::instance(false) == m_timer); + m_timer->unregisterAnimation(this); + } } Q_ASSERT(!m_hasRegisteredTimer); } @@ -308,8 +335,9 @@ void QAbstractAnimationJob::setState(QAbstractAnimationJob::State newState) if (m_loopCount == 0) return; - if (!m_timer) - m_timer = QQmlAnimationTimer::instance(); + if (!m_timer) // don't create a timer just to stop the animation + m_timer = QQmlAnimationTimer::instance(newState != Stopped); + Q_ASSERT(m_timer || newState == Stopped); State oldState = m_state; int oldCurrentTime = m_currentTime; @@ -337,8 +365,9 @@ void QAbstractAnimationJob::setState(QAbstractAnimationJob::State newState) if (oldState == Running) { if (newState == Paused && m_hasRegisteredTimer) m_timer->ensureTimerUpdate(); - //the animation, is not running any more - m_timer->unregisterAnimation(this); + // the animation is not running any more + if (m_timer) + m_timer->unregisterAnimation(this); } else if (newState == Running) { m_timer->registerAnimation(this, isTopLevel); } diff --git a/src/qml/animations/qabstractanimationjob_p.h b/src/qml/animations/qabstractanimationjob_p.h index 9490070246..1010f0f392 100644 --- a/src/qml/animations/qabstractanimationjob_p.h +++ b/src/qml/animations/qabstractanimationjob_p.h @@ -207,6 +207,8 @@ private: QQmlAnimationTimer(); public: + ~QQmlAnimationTimer(); // must be destructible by QThreadStorage + static QQmlAnimationTimer *instance(); static QQmlAnimationTimer *instance(bool create); @@ -252,6 +254,7 @@ private: void registerRunningAnimation(QAbstractAnimationJob *animation); void unregisterRunningAnimation(QAbstractAnimationJob *animation); + void unsetJobTimer(QAbstractAnimationJob *animation); int closestPauseAnimationTimeToFinish(); }; diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 2ad85ab910..36b7f68de9 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1901,6 +1901,12 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil scan.enterEnvironment(f.parentNode, QV4::Compiler::ContextType::Binding, qmlName(f)); } + /* We do not want to visit the whole function, as we already called enterQmlFunction + However, there might be a function defined as a default argument of the function. + That needs to be considered, too, so we call handleTopLevelFunctionFormals to + deal with them. + */ + scan.handleTopLevelFunctionFormals(function); scan(function ? function->body : f.node); scan.leaveEnvironment(); } diff --git a/src/qml/compiler/qv4compilerscanfunctions_p.h b/src/qml/compiler/qv4compilerscanfunctions_p.h index e39aa2454e..56172e2ea5 100644 --- a/src/qml/compiler/qv4compilerscanfunctions_p.h +++ b/src/qml/compiler/qv4compilerscanfunctions_p.h @@ -83,6 +83,13 @@ public: ScanFunctions(Codegen *cg, const QString &sourceCode, ContextType defaultProgramType); void operator()(QQmlJS::AST::Node *node); + // see comment at its call site in generateJSCodeForFunctionsAndBindings + // for why this function is necessary + void handleTopLevelFunctionFormals(QQmlJS::AST::FunctionExpression *node) { + if (node && node->formals) + node->formals->accept(this); + } + void enterGlobalEnvironment(ContextType compilationMode); void enterEnvironment(QQmlJS::AST::Node *node, ContextType compilationMode, const QString &name); diff --git a/src/qml/jit/qv4assemblercommon.cpp b/src/qml/jit/qv4assemblercommon.cpp index 95070fbb96..b090fc7597 100644 --- a/src/qml/jit/qv4assemblercommon.cpp +++ b/src/qml/jit/qv4assemblercommon.cpp @@ -51,6 +51,8 @@ #include <assembler/LinkBuffer.h> #include <WTFStubs.h> +#if QT_CONFIG(qml_jit) + #undef ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES QT_BEGIN_NAMESPACE @@ -370,3 +372,5 @@ void PlatformAssemblerCommon::storeInt32AsValue(int srcInt, Address destAddr) } // QV4 namepsace QT_END_NAMESPACE + +#endif // QT_CONFIG(qml_jit) diff --git a/src/qml/jit/qv4assemblercommon_p.h b/src/qml/jit/qv4assemblercommon_p.h index ead1e757de..c3b1eb34eb 100644 --- a/src/qml/jit/qv4assemblercommon_p.h +++ b/src/qml/jit/qv4assemblercommon_p.h @@ -58,7 +58,7 @@ #include <wtf/Vector.h> #include <assembler/MacroAssembler.h> -QT_REQUIRE_CONFIG(qml_jit); +#if QT_CONFIG(qml_jit) QT_BEGIN_NAMESPACE @@ -740,4 +740,6 @@ private: QT_END_NAMESPACE +#endif // QT_CONFIG(qml_jit) + #endif // QV4PLATFORMASSEMBLER_P_H diff --git a/src/qml/jit/qv4baselineassembler.cpp b/src/qml/jit/qv4baselineassembler.cpp index dd6a40afe0..7ad131335e 100644 --- a/src/qml/jit/qv4baselineassembler.cpp +++ b/src/qml/jit/qv4baselineassembler.cpp @@ -55,6 +55,8 @@ #undef ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES +#if QT_CONFIG(qml_jit) + QT_BEGIN_NAMESPACE namespace QV4 { namespace JIT { @@ -1619,3 +1621,5 @@ void BaselineAssembler::ret() } // QV4 namepsace QT_END_NAMESPACE + +#endif // QT_CONFIG(qml_jit) diff --git a/src/qml/jit/qv4baselineassembler_p.h b/src/qml/jit/qv4baselineassembler_p.h index c2c735282b..c6fdab51c5 100644 --- a/src/qml/jit/qv4baselineassembler_p.h +++ b/src/qml/jit/qv4baselineassembler_p.h @@ -55,7 +55,7 @@ #include <private/qv4function_p.h> #include <QHash> -QT_REQUIRE_CONFIG(qml_jit); +#if QT_CONFIG(qml_jit) QT_BEGIN_NAMESPACE @@ -182,4 +182,6 @@ private: QT_END_NAMESPACE +#endif // QT_CONFIG(qml_jit) + #endif // QV4BASELINEASSEMBLER_P_H diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp index d329a5afec..45150cfffd 100644 --- a/src/qml/jit/qv4baselinejit.cpp +++ b/src/qml/jit/qv4baselinejit.cpp @@ -42,6 +42,8 @@ #include <private/qv4lookup_p.h> #include <private/qv4generatorobject_p.h> +#if QT_CONFIG(qml_jit) + QT_USE_NAMESPACE using namespace QV4; using namespace QV4::JIT; @@ -930,3 +932,6 @@ void BaselineJIT::endInstruction(Instr::Type instr) { Q_UNUSED(instr); } + +#endif // QT_CONFIG(qml_jit) + diff --git a/src/qml/jit/qv4baselinejit_p.h b/src/qml/jit/qv4baselinejit_p.h index 284faf0ff0..2b0913169e 100644 --- a/src/qml/jit/qv4baselinejit_p.h +++ b/src/qml/jit/qv4baselinejit_p.h @@ -56,7 +56,7 @@ #include <private/qv4instr_moth_p.h> #include <private/qv4bytecodehandler_p.h> -QT_REQUIRE_CONFIG(qml_jit); +#if QT_CONFIG(qml_jit) QT_BEGIN_NAMESPACE @@ -220,4 +220,6 @@ private: QT_END_NAMESPACE +#endif // QT_CONFIG(qml_jit) + #endif // QV4JIT_P_H diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp index 2c54388100..5eb0e889b0 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit.cpp +++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp @@ -296,24 +296,8 @@ void ExecutableCompilationUnit::unlink() propertyCaches.clear(); if (runtimeLookups) { - for (uint i = 0; i < data->lookupTableSize; ++i) { - QV4::Lookup &l = runtimeLookups[i]; - if (l.getter == QV4::QObjectWrapper::lookupGetter - || l.getter == QQmlTypeWrapper::lookupSingletonProperty) { - if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache) - pc->release(); - } else if (l.getter == QQmlValueTypeWrapper::lookupGetter - || l.getter == QQmlTypeWrapper::lookupSingletonProperty) { - if (QQmlPropertyCache *pc = l.qgadgetLookup.propertyCache) - pc->release(); - } - - if (l.qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty - || l.qmlContextPropertyGetter == QQmlContextWrapper::lookupContextObjectProperty) { - if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache) - pc->release(); - } - } + for (uint i = 0; i < data->lookupTableSize; ++i) + runtimeLookups[i].releasePropertyCache(); } dependentScripts.clear(); diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index d3ea50867a..db6fb39695 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -41,6 +41,7 @@ #include "qv4jscall_p.h" #include "qv4string_p.h" #include <private/qv4identifiertable_p.h> +#include <private/qv4qobjectwrapper_p.h> QT_BEGIN_NAMESPACE @@ -144,47 +145,76 @@ ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Va return l->resolvePrimitiveGetter(engine, object); } +static inline void setupObjectLookupTwoClasses(Lookup *l, const Lookup &first, const Lookup &second) +{ + Heap::InternalClass *ic1 = first.objectLookup.ic; + const uint offset1 = first.objectLookup.offset; + Heap::InternalClass *ic2 = second.objectLookup.ic; + const uint offset2 = second.objectLookup.offset; + + l->objectLookupTwoClasses.ic = ic1; + l->objectLookupTwoClasses.ic2 = ic2; + l->objectLookupTwoClasses.offset = offset1; + l->objectLookupTwoClasses.offset2 = offset2; +} + +static inline void setupProtoLookupTwoClasses(Lookup *l, const Lookup &first, const Lookup &second) +{ + const quintptr protoId1 = first.protoLookup.protoId; + const Value *data1 = first.protoLookup.data; + const quintptr protoId2 = second.protoLookup.protoId; + const Value *data2 = second.protoLookup.data; + + l->protoLookupTwoClasses.protoId = protoId1; + l->protoLookupTwoClasses.protoId2 = protoId2; + l->protoLookupTwoClasses.data = data1; + l->protoLookupTwoClasses.data2 = data2; +} + ReturnedValue Lookup::getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object) { if (const Object *o = object.as<Object>()) { - Lookup first = *l; - Lookup second = *l; - ReturnedValue result = second.resolveGetter(engine, o); - - if (first.getter == getter0Inline && (second.getter == getter0Inline || second.getter == getter0MemberData)) { - l->objectLookupTwoClasses.ic = first.objectLookup.ic; - l->objectLookupTwoClasses.ic2 = second.objectLookup.ic; - l->objectLookupTwoClasses.offset = first.objectLookup.offset; - l->objectLookupTwoClasses.offset2 = second.objectLookup.offset; - l->getter = second.getter == getter0Inline ? getter0Inlinegetter0Inline : getter0Inlinegetter0MemberData; + // Do the resolution on a second lookup, then merge. + Lookup second; + memset(&second, 0, sizeof(Lookup)); + second.nameIndex = l->nameIndex; + second.getter = getterGeneric; + const ReturnedValue result = second.resolveGetter(engine, o); + + if (l->getter == getter0Inline + && (second.getter == getter0Inline || second.getter == getter0MemberData)) { + setupObjectLookupTwoClasses(l, *l, second); + l->getter = (second.getter == getter0Inline) + ? getter0Inlinegetter0Inline + : getter0Inlinegetter0MemberData; return result; } - if (first.getter == getter0MemberData && (second.getter == getter0Inline || second.getter == getter0MemberData)) { - l->objectLookupTwoClasses.ic = second.objectLookup.ic; - l->objectLookupTwoClasses.ic2 = first.objectLookup.ic; - l->objectLookupTwoClasses.offset = second.objectLookup.offset; - l->objectLookupTwoClasses.offset2 = first.objectLookup.offset; - l->getter = second.getter == getter0Inline ? getter0Inlinegetter0MemberData : getter0MemberDatagetter0MemberData; + + if (l->getter == getter0MemberData + && (second.getter == getter0Inline || second.getter == getter0MemberData)) { + setupObjectLookupTwoClasses(l, second, *l); + l->getter = (second.getter == getter0Inline) + ? getter0Inlinegetter0MemberData + : getter0MemberDatagetter0MemberData; return result; } - if (first.getter == getterProto && second.getter == getterProto) { - l->protoLookupTwoClasses.protoId = first.protoLookup.protoId; - l->protoLookupTwoClasses.protoId2 = second.protoLookup.protoId; - l->protoLookupTwoClasses.data = first.protoLookup.data; - l->protoLookupTwoClasses.data2 = second.protoLookup.data; + + + if (l->getter == getterProto && second.getter == getterProto) { + setupProtoLookupTwoClasses(l, *l, second); l->getter = getterProtoTwoClasses; return result; } - if (first.getter == getterProtoAccessor && second.getter == getterProtoAccessor) { - l->protoLookupTwoClasses.protoId = first.protoLookup.protoId; - l->protoLookupTwoClasses.protoId2 = second.protoLookup.protoId; - l->protoLookupTwoClasses.data = first.protoLookup.data; - l->protoLookupTwoClasses.data2 = second.protoLookup.data; + + if (l->getter == getterProtoAccessor && second.getter == getterProtoAccessor) { + setupProtoLookupTwoClasses(l, *l, second); l->getter = getterProtoAccessorTwoClasses; return result; } + // If any of the above options were true, the propertyCache was inactive. + second.releasePropertyCache(); } l->getter = getterFallback; @@ -371,7 +401,19 @@ ReturnedValue Lookup::getterIndexed(Lookup *l, ExecutionEngine *engine, const Va } l->getter = getterFallback; return getterFallback(l, engine, object); +} +ReturnedValue Lookup::getterQObject(Lookup *lookup, ExecutionEngine *engine, const Value &object) +{ + const auto revertLookup = [lookup, engine, &object]() { + lookup->qobjectLookup.propertyCache->release(); + lookup->qobjectLookup.propertyCache = nullptr; + lookup->getter = Lookup::getterGeneric; + return Lookup::getterGeneric(lookup, engine, object); + }; + + return QObjectWrapper::lookupGetterImpl( + lookup, engine, object, /*useOriginalProperty*/ false, revertLookup); } ReturnedValue Lookup::primitiveGetterProto(Lookup *l, ExecutionEngine *engine, const Value &object) @@ -463,23 +505,30 @@ bool Lookup::setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, co bool Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Lookup first = *l; - Lookup second = *l; + // A precondition of this method is that l->objectLookup is the active variant of the union. + Q_ASSERT(l->setter == setter0MemberData || l->setter == setter0Inline); if (object.isObject()) { + + // As l->objectLookup is active, we can stash some members here, before resolving. + Heap::InternalClass *ic = l->objectLookup.ic; + const uint index = l->objectLookup.index; + if (!l->resolveSetter(engine, static_cast<Object *>(&object), value)) { l->setter = setterFallback; return false; } if (l->setter == Lookup::setter0MemberData || l->setter == Lookup::setter0Inline) { - l->objectLookupTwoClasses.ic = first.objectLookup.ic; - l->objectLookupTwoClasses.ic2 = second.objectLookup.ic; - l->objectLookupTwoClasses.offset = first.objectLookup.index; - l->objectLookupTwoClasses.offset2 = second.objectLookup.index; + l->objectLookupTwoClasses.ic = ic; + l->objectLookupTwoClasses.ic2 = ic; + l->objectLookupTwoClasses.offset = index; + l->objectLookupTwoClasses.offset2 = index; l->setter = setter0setter0; return true; } + + l->releasePropertyCache(); } l->setter = setterFallback; diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index 31c90b31f6..6241a81850 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -56,11 +56,17 @@ #include "qv4context_p.h" #include "qv4object_p.h" #include "qv4internalclass_p.h" +#include "qv4qmlcontext_p.h" +#include <private/qqmltypewrapper_p.h> +#include <private/qqmlvaluetypewrapper_p.h> QT_BEGIN_NAMESPACE namespace QV4 { +// Note: We cannot hide the copy ctor and assignment operator of this class because it needs to +// be trivially copyable. But you should never ever copy it. There are refcounted members +// in there. struct Q_QML_PRIVATE_EXPORT Lookup { union { ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object); @@ -187,6 +193,7 @@ struct Q_QML_PRIVATE_EXPORT Lookup { static ReturnedValue getterProtoAccessor(Lookup *l, ExecutionEngine *engine, const Value &object); static ReturnedValue getterProtoAccessorTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object); static ReturnedValue getterIndexed(Lookup *l, ExecutionEngine *engine, const Value &object); + static ReturnedValue getterQObject(Lookup *l, ExecutionEngine *engine, const Value &object); static ReturnedValue primitiveGetterProto(Lookup *l, ExecutionEngine *engine, const Value &object); static ReturnedValue primitiveGetterAccessor(Lookup *l, ExecutionEngine *engine, const Value &object); @@ -216,6 +223,20 @@ struct Q_QML_PRIVATE_EXPORT Lookup { void clear() { memset(&markDef, 0, sizeof(markDef)); } + + void releasePropertyCache() + { + if (getter == getterQObject + || getter == QQmlTypeWrapper::lookupSingletonProperty + || qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty + || qmlContextPropertyGetter == QQmlContextWrapper::lookupContextObjectProperty) { + if (QQmlPropertyCache *pc = qobjectLookup.propertyCache) + pc->release(); + } else if (getter == QQmlValueTypeWrapper::lookupGetter) { + if (QQmlPropertyCache *pc = qgadgetLookup.propertyCache) + pc->release(); + } + } }; Q_STATIC_ASSERT(std::is_standard_layout<Lookup>::value); @@ -223,6 +244,33 @@ Q_STATIC_ASSERT(std::is_standard_layout<Lookup>::value); // across 32-bit and 64-bit (matters when cross-compiling). Q_STATIC_ASSERT(offsetof(Lookup, getter) == 0); +inline void setupQObjectLookup( + Lookup *lookup, const QQmlData *ddata, QQmlPropertyData *propertyData) +{ + lookup->releasePropertyCache(); + Q_ASSERT(ddata->propertyCache != nullptr); + lookup->qobjectLookup.propertyCache = ddata->propertyCache; + lookup->qobjectLookup.propertyCache->addref(); + lookup->qobjectLookup.propertyData = propertyData; +} + +inline void setupQObjectLookup( + Lookup *lookup, const QQmlData *ddata, QQmlPropertyData *propertyData, + const Object *self) +{ + lookup->qobjectLookup.ic = self->internalClass(); + setupQObjectLookup(lookup, ddata, propertyData); +} + + +inline void setupQObjectLookup( + Lookup *lookup, const QQmlData *ddata, QQmlPropertyData *propertyData, + const Object *self, const Object *qmlType) +{ + lookup->qobjectLookup.qmlTypeIc = qmlType->internalClass(); + setupQObjectLookup(lookup, ddata, propertyData, self); +} + } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index 6eece147a6..be6c614eda 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -294,11 +294,7 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r QQmlData *ddata = QQmlData::get(scopeObject, false); if (ddata && ddata->propertyCache) { ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, scopeObject))); - const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue()); - lookup->qobjectLookup.ic = That->internalClass(); - lookup->qobjectLookup.propertyCache = ddata->propertyCache; - lookup->qobjectLookup.propertyCache->addref(); - lookup->qobjectLookup.propertyData = propertyData; + QV4::setupQObjectLookup(lookup, ddata, propertyData, val->objectValue()); lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupScopeObjectProperty; } } @@ -326,11 +322,8 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r QQmlData *ddata = QQmlData::get(context->contextObject, false); if (ddata && ddata->propertyCache) { ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, context->contextObject))); - const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue()); - lookup->qobjectLookup.ic = That->internalClass(); - lookup->qobjectLookup.propertyCache = ddata->propertyCache; - lookup->qobjectLookup.propertyCache->addref(); - lookup->qobjectLookup.propertyData = propertyData; + QV4::setupQObjectLookup(lookup, ddata, propertyData, + val->objectValue()); lookup->qmlContextPropertyGetter = contextGetterFunction; } } else if (originalLookup) { diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 9899c9274e..e57cdd8278 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -875,26 +875,11 @@ ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, E return QV4::Object::virtualResolveLookupGetter(object, engine, lookup); } - lookup->qobjectLookup.ic = This->internalClass(); - lookup->qobjectLookup.propertyCache = ddata->propertyCache; - lookup->qobjectLookup.propertyCache->addref(); - lookup->qobjectLookup.propertyData = property; - lookup->getter = QV4::QObjectWrapper::lookupGetter; + QV4::setupQObjectLookup(lookup, ddata, property, This); + lookup->getter = QV4::Lookup::getterQObject; return lookup->getter(lookup, engine, *object); } -ReturnedValue QObjectWrapper::lookupGetter(Lookup *lookup, ExecutionEngine *engine, const Value &object) -{ - const auto revertLookup = [lookup, engine, &object]() { - lookup->qobjectLookup.propertyCache->release(); - lookup->qobjectLookup.propertyCache = nullptr; - lookup->getter = Lookup::getterGeneric; - return Lookup::getterGeneric(lookup, engine, object); - }; - - return lookupGetterImpl(lookup, engine, object, /*useOriginalProperty*/ false, revertLookup); -} - bool QObjectWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value) { diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index ac9cad2bdb..10ba79a5e9 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -183,7 +183,7 @@ struct Q_QML_EXPORT QObjectWrapper : public Object static ReturnedValue getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property); static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup); - static ReturnedValue lookupGetter(Lookup *l, ExecutionEngine *engine, const Value &object); + template <typename ReversalFunctor> static ReturnedValue lookupGetterImpl(Lookup *l, ExecutionEngine *engine, const Value &object, bool useOriginalProperty, ReversalFunctor revert); static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value); diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 9eb81e566e..92bd369ccc 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -598,12 +598,8 @@ QObject *QQmlProperty::object() const */ QQmlProperty &QQmlProperty::operator=(const QQmlProperty &other) { - if (d) - d->release(); - d = other.d; - if (d) - d->addref(); - + QQmlProperty copied(other); + qSwap(d, copied.d); return *this; } diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp index 92a90ea677..ebd139b6a9 100644 --- a/src/qml/qml/qqmltypedata.cpp +++ b/src/qml/qml/qqmltypedata.cpp @@ -211,18 +211,12 @@ bool QQmlTypeData::tryLoadFromDiskCache() } } - QQmlType containingType; - auto containingTypeName = finalUrl().fileName().split(QLatin1Char('.')).first(); - int major = -1, minor = -1; - QQmlImportNamespace *ns = nullptr; - m_importCache.resolveType(containingTypeName, &containingType, &major, &minor, &ns); for (auto&& ic: ics) { QString const nameString = m_compiledData->stringAt(ic.nameIndex); - QByteArray const name = nameString.toUtf8(); auto importUrl = finalUrl(); importUrl.setFragment(QString::number(ic.objectIndex)); auto import = new QQmlImportInstance(); - m_importCache.addInlineComponentImport(import, nameString, importUrl, containingType); + m_importCache.addInlineComponentImport(import, nameString, importUrl, QQmlType()); } return true; diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index fa5d36503d..175de8b936 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -458,11 +458,8 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object, QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext); if (property) { ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton))); - lookup->qobjectLookup.qmlTypeIc = This->internalClass(); - lookup->qobjectLookup.ic = val->objectValue()->internalClass(); - lookup->qobjectLookup.propertyCache = ddata->propertyCache; - lookup->qobjectLookup.propertyCache->addref(); - lookup->qobjectLookup.propertyData = property; + setupQObjectLookup(lookup, ddata, property, + val->objectValue(), This); lookup->getter = QQmlTypeWrapper::lookupSingletonProperty; return lookup->getter(lookup, engine, *object); } diff --git a/src/qml/qtqmlglobal_p.h b/src/qml/qtqmlglobal_p.h index 7b0910fa13..76479431dc 100644 --- a/src/qml/qtqmlglobal_p.h +++ b/src/qml/qtqmlglobal_p.h @@ -70,4 +70,26 @@ GHS_KEEP_REFERENCE(qml_register_types_QtQml); # define Q_QML_AUTOTEST_EXPORT #endif +// When doing macOS universal builds, JIT needs to be disabled for the ARM slice. +// Because both arm and x86_64 slices are built in one clang frontend invocation +// we need this hack to ensure each backend invocation sees the correct value +// of the feature definition. + +// Unset dummy value +#undef QT_QML_JIT_SUPPORTED_IMPL +// Compute per-arch value and save in extra define +#if QT_CONFIG(qml_jit) && !(defined(Q_OS_MACOS) && defined(Q_PROCESSOR_ARM)) +# define QT_QML_JIT_SUPPORTED_IMPL 1 +#else +# define QT_QML_JIT_SUPPORTED_IMPL 0 +#endif +// Unset original feature value +#undef QT_FEATURE_qml_jit +// Set new value based on previous computation +#if QT_QML_JIT_SUPPORTED_IMPL +# define QT_FEATURE_qml_jit 1 +#else +# define QT_FEATURE_qml_jit -1 +#endif + #endif // QTQMLGLOBAL_P_H diff --git a/src/qmltyperegistrar/qmltypes.prf b/src/qmltyperegistrar/qmltypes.prf index 2cc0027b7e..471bb6e3b0 100644 --- a/src/qmltyperegistrar/qmltypes.prf +++ b/src/qmltyperegistrar/qmltypes.prf @@ -81,12 +81,18 @@ qmltyperegistrar_compiler.output = $$TYPEREGISTRATIONS qmltyperegistrar_compiler.variable_out = SOURCES qmltyperegistrar_compiler.name = Automatic QML type registration qmltyperegistrar_compiler.dependency_type = TYPE_C - -qmltyperegistrar_qmltypes.input = METATYPES_JSON -qmltyperegistrar_qmltypes.depends = $$TYPEREGISTRATIONS -qmltyperegistrar_qmltypes.output = $$QMLTYPES_FILENAME -qmltyperegistrar_qmltypes.CONFIG = no_link -qmltyperegistrar_qmltypes.commands = $$escape_expand(\\n) # force creation of rule +QMAKE_EXTRA_COMPILERS += qmltyperegistrar_compiler + +!contains(TEMPLATE, "vc.*") { # work around QTBUG-91033 + # Create a fake extra compiler to announce that we generate $$QMLTYPES_FILENAME. + # This allows us to use $$QMLTYPES_FILENAME as input in other extra compilers. + qmltyperegistrar_qmltypes.input = METATYPES_JSON + qmltyperegistrar_qmltypes.depends = $$TYPEREGISTRATIONS + qmltyperegistrar_qmltypes.output = $$QMLTYPES_FILENAME + qmltyperegistrar_qmltypes.CONFIG = no_link + qmltyperegistrar_qmltypes.commands = $$escape_expand(\\n) # force creation of rule + QMAKE_EXTRA_COMPILERS += qmltyperegistrar_qmltypes +} install_qmltypes { INSTALL_QML_FILES = false @@ -109,5 +115,3 @@ install_qmltypes { else: COPIES += do_install_qmltypes } } - -QMAKE_EXTRA_COMPILERS += qmltyperegistrar_compiler qmltyperegistrar_qmltypes diff --git a/src/quick/handlers/qquickhoverhandler.cpp b/src/quick/handlers/qquickhoverhandler.cpp index b12d85784a..3361415eac 100644 --- a/src/quick/handlers/qquickhoverhandler.cpp +++ b/src/quick/handlers/qquickhoverhandler.cpp @@ -85,8 +85,11 @@ QQuickHoverHandler::~QQuickHoverHandler() void QQuickHoverHandler::componentComplete() { - parentItem()->setAcceptHoverEvents(true); - QQuickItemPrivate::get(parentItem())->setHasHoverInChild(true); + QQuickSinglePointHandler::componentComplete(); + if (auto par = parentItem()) { + par->setAcceptHoverEvents(true); + QQuickItemPrivate::get(par)->setHasHoverInChild(true); + } } bool QQuickHoverHandler::wantsPointerEvent(QQuickPointerEvent *event) @@ -124,6 +127,13 @@ void QQuickHoverHandler::handleEventPoint(QQuickEventPoint *point) setPassiveGrab(point); } +void QQuickHoverHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point) +{ + QQuickSinglePointHandler::onGrabChanged(grabber, transition, point); + if (grabber == this && transition == QQuickEventPoint::CancelGrabPassive) + setHovered(false); +} + /*! \qmlproperty bool QtQuick::HoverHandler::hovered \readonly diff --git a/src/quick/handlers/qquickhoverhandler_p.h b/src/quick/handlers/qquickhoverhandler_p.h index 313b87217c..426372d162 100644 --- a/src/quick/handlers/qquickhoverhandler_p.h +++ b/src/quick/handlers/qquickhoverhandler_p.h @@ -78,6 +78,7 @@ protected: void componentComplete() override; bool wantsPointerEvent(QQuickPointerEvent *event) override; void handleEventPoint(QQuickEventPoint *point) override; + void onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point) override; private: void setHovered(bool hovered); diff --git a/src/quick/handlers/qquickpointerhandler.cpp b/src/quick/handlers/qquickpointerhandler.cpp index a6c18feafe..25c5e684b7 100644 --- a/src/quick/handlers/qquickpointerhandler.cpp +++ b/src/quick/handlers/qquickpointerhandler.cpp @@ -207,9 +207,11 @@ void QQuickPointerHandler::setCursorShape(Qt::CursorShape shape) return; d->cursorShape = shape; d->cursorSet = true; - QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parentItem()); - itemPriv->hasCursorHandler = true; - itemPriv->setHasCursorInChild(true); + if (auto *par = qmlobject_cast<QQuickItem *>(parent())) { + QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(par); + itemPriv->hasCursorHandler = true; + itemPriv->setHasCursorInChild(true); + } emit cursorShapeChanged(); } @@ -220,9 +222,11 @@ void QQuickPointerHandler::resetCursorShape() return; d->cursorShape = Qt::ArrowCursor; d->cursorSet = false; - QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parentItem()); - itemPriv->hasCursorHandler = false; - itemPriv->setHasCursorInChild(itemPriv->hasCursor); + if (auto *parent = parentItem()) { + QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parent); + itemPriv->hasCursorHandler = false; + itemPriv->setHasCursorInChild(itemPriv->hasCursor); + } emit cursorShapeChanged(); } @@ -457,6 +461,14 @@ void QQuickPointerHandler::classBegin() void QQuickPointerHandler::componentComplete() { + Q_D(const QQuickPointerHandler); + if (d->cursorSet) { + if (auto *parent = parentItem()) { + QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parent); + itemPriv->hasCursorHandler = true; + itemPriv->setHasCursorInChild(true); + } + } } QQuickPointerEvent *QQuickPointerHandler::currentEvent() diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp index f239f24367..8818bc5608 100644 --- a/src/quick/items/qquickanimatedsprite.cpp +++ b/src/quick/items/qquickanimatedsprite.cpp @@ -894,7 +894,7 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGSpriteNode *node) maybeUpdate(); } - qreal frameCount = d->m_spriteEngine->spriteFrames(); + int frameCount = d->m_spriteEngine->spriteFrames(); bool reverse = d->m_spriteEngine->sprite()->reverse(); if (reverse) frameAt = (frameCount - 1) - frameAt; @@ -931,15 +931,15 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGSpriteNode *node) x2 = x1 - w; y2 = y1; } else { - x2 = 1.0 - w; + x2 = d->m_sheetSize.width() - w; y2 = y1 - h; - if (y2 < 0.0) { + if (y2 < 0) { //the last row may not fill the entire width int maxRowFrames = d->m_sheetSize.width() / d->m_spriteEngine->spriteWidth(); if (d->m_spriteEngine->maxFrames() % maxRowFrames) x2 = ((d->m_spriteEngine->maxFrames() % maxRowFrames) - 1) * w; - y2 = 1.0 - h; + y2 = d->m_sheetSize.height() - h; } } } else { @@ -947,10 +947,10 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGSpriteNode *node) x2 = x1 + w; y2 = y1; } else { - x2 = 0.0; + x2 = 0; y2 = y1 + h; - if (y2 >= 1.0) - y2 = 0.0; + if (y2 >= d->m_sheetSize.height()) + y2 = 0; } } diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index e12e85db64..7bf242a527 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -62,6 +62,8 @@ QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(lcHandlerParent) +Q_LOGGING_CATEGORY(lcVel, "qt.quick.flickable.velocity") +Q_LOGGING_CATEGORY(lcWheel, "qt.quick.flickable.wheel") // FlickThreshold determines how far the "mouse" must have moved // before we perform a flick. @@ -263,7 +265,8 @@ QQuickFlickablePrivate::QQuickFlickablePrivate() , deceleration(QML_FLICK_DEFAULTDECELERATION) , maxVelocity(QML_FLICK_DEFAULTMAXVELOCITY), reportedVelocitySmoothing(100) , delayedPressEvent(nullptr), pressDelay(0), fixupDuration(400) - , flickBoost(1.0), fixupMode(Normal), vTime(0), visibleArea(nullptr) + , flickBoost(1.0), initialWheelFlickDistance(qApp->styleHints()->wheelScrollLines() * 24) + , fixupMode(Normal), vTime(0), visibleArea(nullptr) , flickableDirection(QQuickFlickable::AutoFlickDirection) , boundsBehavior(QQuickFlickable::DragAndOvershootBounds) , boundsMovement(QQuickFlickable::FollowBoundsBehavior) @@ -531,10 +534,14 @@ void QQuickFlickablePrivate::updateBeginningEnd() if (atBeginning != vData.atBeginning) { vData.atBeginning = atBeginning; atYBeginningChange = true; + if (!vData.moving && atBeginning) + vData.smoothVelocity.setValue(0); } if (atEnd != vData.atEnd) { vData.atEnd = atEnd; atYEndChange = true; + if (!vData.moving && atEnd) + vData.smoothVelocity.setValue(0); } // Horizontal @@ -547,10 +554,14 @@ void QQuickFlickablePrivate::updateBeginningEnd() if (atBeginning != hData.atBeginning) { hData.atBeginning = atBeginning; atXBeginningChange = true; + if (!hData.moving && atBeginning) + hData.smoothVelocity.setValue(0); } if (atEnd != hData.atEnd) { hData.atEnd = atEnd; atXEndChange = true; + if (!hData.moving && atEnd) + hData.smoothVelocity.setValue(0); } if (vData.extentsChanged) { @@ -1489,6 +1500,7 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event) d->hData.velocity = 0; d->timer.start(); d->maybeBeginDrag(currentTimestamp, event->position()); + d->lastPosTime = -1; break; case Qt::NoScrollPhase: // default phase with an ordinary wheel mouse case Qt::ScrollUpdate: @@ -1515,20 +1527,34 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event) return; } + qreal elapsed = qreal(currentTimestamp - d->lastPosTime) / qreal(1000); + if (elapsed <= 0) { + d->lastPosTime = currentTimestamp; + qCDebug(lcWheel) << "insufficient elapsed time: can't calculate velocity" << elapsed; + return; + } + if (event->source() == Qt::MouseEventNotSynthesized || event->pixelDelta().isNull()) { - // physical mouse wheel, so use angleDelta + // no pixel delta (physical mouse wheel, or "dumb" touchpad), so use angleDelta int xDelta = event->angleDelta().x(); int yDelta = event->angleDelta().y(); + // For a single "clicky" wheel event (angleDelta +/- 120), + // we want flick() to end up moving a distance proportional to QStyleHints::wheelScrollLines(). + // The decel algo from there is + // qreal dist = v2 / (accel * 2.0); + // i.e. initialWheelFlickDistance = (120 / dt)^2 / (deceleration * 2) + // now solve for dt: + // dt = 120 / sqrt(deceleration * 2 * initialWheelFlickDistance) + if (!isMoving()) + elapsed = 120 / qSqrt(d->deceleration * 2 * d->initialWheelFlickDistance); if (yflick() && yDelta != 0) { - bool valid = false; - if (yDelta > 0 && contentY() > -minYExtent()) { - d->vData.velocity = qMax(yDelta*2 - d->vData.smoothVelocity.value(), qreal(d->maxVelocity/4)); - valid = true; - } else if (yDelta < 0 && contentY() < -maxYExtent()) { - d->vData.velocity = qMin(yDelta*2 - d->vData.smoothVelocity.value(), qreal(-d->maxVelocity/4)); - valid = true; - } - if (valid) { + qreal instVelocity = yDelta / elapsed; + // if the direction has changed, start over with filtering, to allow instant movement in the opposite direction + if ((instVelocity < 0 && d->vData.velocity > 0) || (instVelocity > 0 && d->vData.velocity < 0)) + d->vData.velocityBuffer.clear(); + d->vData.addVelocitySample(instVelocity, d->maxVelocity); + d->vData.updateVelocity(); + if ((yDelta > 0 && contentY() > -minYExtent()) || (yDelta < 0 && contentY() < -maxYExtent())) { d->flickY(d->vData.velocity); d->flickingStarted(false, true); if (d->vData.flicking) { @@ -1539,15 +1565,13 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event) } } if (xflick() && xDelta != 0) { - bool valid = false; - if (xDelta > 0 && contentX() > -minXExtent()) { - d->hData.velocity = qMax(xDelta*2 - d->hData.smoothVelocity.value(), qreal(d->maxVelocity/4)); - valid = true; - } else if (xDelta < 0 && contentX() < -maxXExtent()) { - d->hData.velocity = qMin(xDelta*2 - d->hData.smoothVelocity.value(), qreal(-d->maxVelocity/4)); - valid = true; - } - if (valid) { + qreal instVelocity = xDelta / elapsed; + // if the direction has changed, start over with filtering, to allow instant movement in the opposite direction + if ((instVelocity < 0 && d->hData.velocity > 0) || (instVelocity > 0 && d->hData.velocity < 0)) + d->hData.velocityBuffer.clear(); + d->hData.addVelocitySample(instVelocity, d->maxVelocity); + d->hData.updateVelocity(); + if ((xDelta > 0 && contentX() > -minXExtent()) || (xDelta < 0 && contentX() < -maxXExtent())) { d->flickX(d->hData.velocity); d->flickingStarted(true, false); if (d->hData.flicking) { @@ -1562,18 +1586,13 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event) int xDelta = event->pixelDelta().x(); int yDelta = event->pixelDelta().y(); - qreal elapsed = qreal(currentTimestamp - d->lastPosTime) / 1000.; - if (elapsed <= 0) { - d->lastPosTime = currentTimestamp; - return; - } QVector2D velocity(xDelta / elapsed, yDelta / elapsed); - d->lastPosTime = currentTimestamp; d->accumulatedWheelPixelDelta += QVector2D(event->pixelDelta()); d->drag(currentTimestamp, event->type(), event->position(), d->accumulatedWheelPixelDelta, true, !d->scrollingPhase, true, velocity); event->accept(); } + d->lastPosTime = currentTimestamp; if (!event->isAccepted()) QQuickItem::wheelEvent(event); @@ -1744,6 +1763,10 @@ void QQuickFlickable::componentComplete() setContentX(-minXExtent()); if (!d->vData.explicitValue && d->vData.startMargin != 0.) setContentY(-minYExtent()); + if (lcWheel().isDebugEnabled() || lcVel().isDebugEnabled()) { + d->timeline.setObjectName(QLatin1String("timeline for Flickable ") + objectName()); + d->velocityTimeline.setObjectName(QLatin1String("velocity timeline for Flickable ") + objectName()); + } } void QQuickFlickable::viewportMoved(Qt::Orientations orient) @@ -2504,9 +2527,23 @@ void QQuickFlickable::setMaximumFlickVelocity(qreal v) /*! \qmlproperty real QtQuick::Flickable::flickDeceleration - This property holds the rate at which a flick will decelerate. - - The default value is platform dependent. + This property holds the rate at which a flick will decelerate: + the higher the number, the faster it slows down when the user stops + flicking via touch, touchpad or mouse wheel. For example 0.0001 is nearly + "frictionless", and 10000 feels quite "sticky". + + The default value is platform dependent. Values of zero or less are not allowed. + + \note For touchpad flicking, some platforms drive Flickable directly by + sending QWheelEvents with QWheelEvent::phase() being \c Qt::ScrollMomentum, + after the user has released all fingers from the touchpad. In that case, + the operating system is controlling the deceleration, and this property has + no effect. + + \note For mouse wheel scrolling, and for gesture scrolling on touchpads + that do not have a momentum phase, extremely large values of + flickDeceleration can make Flickable very resistant to scrolling, + especially if \l maximumFlickVelocity is too small. */ qreal QQuickFlickable::flickDeceleration() const { @@ -2519,7 +2556,7 @@ void QQuickFlickable::setFlickDeceleration(qreal deceleration) Q_D(QQuickFlickable); if (deceleration == d->deceleration) return; - d->deceleration = deceleration; + d->deceleration = qMax(0.001, deceleration); emit flickDecelerationChanged(); } diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h index 414c9c33d6..6163613493 100644 --- a/src/quick/items/qquickflickable_p_p.h +++ b/src/quick/items/qquickflickable_p_p.h @@ -241,6 +241,7 @@ public: int pressDelay; int fixupDuration; qreal flickBoost; + qreal initialWheelFlickDistance; enum FixupMode { Normal, Immediate, ExtentChanged }; FixupMode fixupMode; diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 13e7b87049..010a0152e1 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -2402,8 +2402,6 @@ void QQuickItemView::createdItem(int index, QObject* object) d->repositionPackageItemAt(item, index); else if (index == d->currentIndex) d->updateCurrent(index); - } else if (index == d->currentIndex) { - d->updateCurrent(index); } } diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp index 4f61d61309..b298ed74da 100644 --- a/src/quick/items/qquickshadereffectsource.cpp +++ b/src/quick/items/qquickshadereffectsource.cpp @@ -344,7 +344,6 @@ void QQuickShaderEffectSource::setSourceItem(QQuickItem *item) d->refFromEffectItem(m_hideSource); d->addItemChangeListener(this, QQuickItemPrivate::Geometry); connect(m_sourceItem, SIGNAL(destroyed(QObject*)), this, SLOT(sourceItemDestroyed(QObject*))); - connect(m_sourceItem, SIGNAL(parentChanged(QQuickItem*)), this, SLOT(sourceItemParentChanged(QQuickItem*))); } else { qWarning("ShaderEffectSource: sourceItem and ShaderEffectSource must both be children of the same window."); m_sourceItem = nullptr; @@ -364,13 +363,6 @@ void QQuickShaderEffectSource::sourceItemDestroyed(QObject *item) } -void QQuickShaderEffectSource::sourceItemParentChanged(QQuickItem *parent) -{ - if (!parent && m_texture) - m_texture->setItem(0); -} - - /*! \qmlproperty rect QtQuick::ShaderEffectSource::sourceRect diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h index 4deb6c70a3..c0a1ccab78 100644 --- a/src/quick/items/qquickshadereffectsource_p.h +++ b/src/quick/items/qquickshadereffectsource_p.h @@ -173,7 +173,6 @@ Q_SIGNALS: private Q_SLOTS: void sourceItemDestroyed(QObject *item); void invalidateSceneGraph(); - void sourceItemParentChanged(QQuickItem *parent); protected: void releaseResources() override; diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index bfdb107ef8..97ece4e10d 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -3458,7 +3458,12 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event) for (int i = 0; i < event->attributes().size(); ++i) { const QInputMethodEvent::Attribute &a = event->attributes().at(i); if (a.type == QInputMethodEvent::Selection) { - m_cursor = qBound(0, a.start + a.length, m_text.length()); + // If we already called internalInsert(), the cursor position will + // already be adjusted correctly. The attribute.start does + // not seem to take the mask into account, so it will reset cursor + // to an invalid position in such case. + if (!cursorPositionChanged) + m_cursor = qBound(0, a.start + a.length, m_text.length()); if (a.length) { m_selstart = qMax(0, qMin(a.start, m_text.length())); m_selend = m_cursor; diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 2b9810ed57..ce32d5aa33 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -2146,6 +2146,15 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems.at(0))) { QQuickItem *hoverLeaveItem = hoverItems.takeFirst(); sendHoverEvent(QEvent::HoverLeave, hoverLeaveItem, scenePos, lastScenePos, modifiers, timestamp, accepted); + QQuickItemPrivate *hoverLeaveItemPrivate = QQuickItemPrivate::get(hoverLeaveItem); + if (hoverLeaveItemPrivate->hasPointerHandlers()) { + for (QQuickPointerHandler *handler : hoverLeaveItemPrivate->extra->pointerHandlers) { + if (auto *hh = qmlobject_cast<QQuickHoverHandler *>(handler)) { + QQuickPointerEvent *pointerEvent = pointerEventInstance(QQuickPointerDevice::genericMouseDevice(), QEvent::MouseMove); + pointerEvent->point(0)->cancelPassiveGrab(hh); + } + } + } } if (!hoverItems.isEmpty() && hoverItems.at(0) == item) {//Not entering a new Item @@ -2190,6 +2199,8 @@ bool QQuickWindowPrivate::deliverSinglePointEventUntilAccepted(QQuickPointerEven QVector<QQuickItem *> targetItems = pointerTargets(contentItem, point, false, false); for (QQuickItem *item : targetItems) { + if (!item->window()) + continue; QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); event->localize(item); // Let Pointer Handlers have the first shot diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index ec65dce95b..77bac7c8a5 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -1133,6 +1133,9 @@ void Renderer::releaseCachedResources() if (m_rhi) m_rhi->releaseCachedResources(); + + m_vertexUploadPool.resize(0); + m_indexUploadPool.resize(0); } void Renderer::invalidateAndRecycleBatch(Batch *b) @@ -4006,6 +4009,16 @@ void Renderer::renderBatches() if (m_useDepthBuffer) { glClearDepthf(1); // calls glClearDepth() under the hood for desktop OpenGL + } + glColorMask(true, true, true, true); + glDisable(GL_SCISSOR_TEST); + + bindable()->clear(clearMode()); + + if (m_renderPassRecordingCallbacks.start) + m_renderPassRecordingCallbacks.start(m_renderPassRecordingCallbacks.userData); + + if (m_useDepthBuffer) { glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glDepthMask(true); @@ -4019,11 +4032,6 @@ void Renderer::renderBatches() glDisable(GL_SCISSOR_TEST); glDisable(GL_STENCIL_TEST); - bindable()->clear(clearMode()); - - if (m_renderPassRecordingCallbacks.start) - m_renderPassRecordingCallbacks.start(m_renderPassRecordingCallbacks.userData); - if (Q_LIKELY(renderOpaque)) { for (int i=0; i<m_opaqueBatches.size(); ++i) { Batch *b = m_opaqueBatches.at(i); diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h index 742a4d03b2..04f1f2732c 100644 --- a/src/quick/scenegraph/qsgadaptationlayer_p.h +++ b/src/quick/scenegraph/qsgadaptationlayer_p.h @@ -465,9 +465,9 @@ public: { return pixelSize / QT_DISTANCEFIELD_BASEFONTSIZE(m_doubleGlyphResolution); } - int distanceFieldRadius() const + qreal distanceFieldRadius() const { - return QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) / QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution); + return QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution)); } int glyphCount() const { return m_glyphCount; } bool doubleGlyphResolution() const { return m_doubleGlyphResolution; } diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp index 0fd6581dc4..f912da5799 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp @@ -119,7 +119,8 @@ public: protected: void initialize() override; - int m_matrix_id; + int m_projectionMatrix_id; + int m_modelViewMatrix_id; int m_color_id; int m_textureScale_id; float m_devicePixelRatio; @@ -135,7 +136,8 @@ char const *const *QSGTextMaskShader::attributeNames() const QSGTextMaskShader::QSGTextMaskShader(QFontEngine::GlyphFormat glyphFormat) : QSGMaterialShader(*new QSGMaterialShaderPrivate) - , m_matrix_id(-1) + , m_projectionMatrix_id(-1) + , m_modelViewMatrix_id(-1) , m_color_id(-1) , m_textureScale_id(-1) , m_glyphFormat(glyphFormat) @@ -146,7 +148,8 @@ QSGTextMaskShader::QSGTextMaskShader(QFontEngine::GlyphFormat glyphFormat) void QSGTextMaskShader::initialize() { - m_matrix_id = program()->uniformLocation("matrix"); + m_projectionMatrix_id = program()->uniformLocation("projectionMatrix"); + m_modelViewMatrix_id = program()->uniformLocation("modelViewMatrix"); m_color_id = program()->uniformLocation("color"); m_textureScale_id = program()->uniformLocation("textureScale"); m_devicePixelRatio = (float) qsg_device_pixel_ratio(QOpenGLContext::currentContext()); @@ -184,8 +187,10 @@ void QSGTextMaskShader::updateState(const RenderState &state, QSGMaterial *newEf program()->setUniformValue("dpr", m_devicePixelRatio); } - if (state.isMatrixDirty()) - program()->setUniformValue(m_matrix_id, state.combinedMatrix()); + if (state.isMatrixDirty()) { + program()->setUniformValue(m_projectionMatrix_id, state.projectionMatrix()); + program()->setUniformValue(m_modelViewMatrix_id, state.modelViewMatrix()); + } } class QSG8BitTextMaskShader : public QSGTextMaskShader @@ -387,8 +392,10 @@ void QSGStyledTextShader::updateState(const RenderState &state, } } - if (state.isMatrixDirty()) - program()->setUniformValue(m_matrix_id, state.combinedMatrix()); + if (state.isMatrixDirty()) { + program()->setUniformValue(m_projectionMatrix_id, state.projectionMatrix()); + program()->setUniformValue(m_modelViewMatrix_id, state.modelViewMatrix()); + } } class QSGOutlinedTextShader : public QSGStyledTextShader diff --git a/src/quick/scenegraph/qsgopengldistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgopengldistancefieldglyphcache.cpp index b6b6f3b057..6e9894b10b 100644 --- a/src/quick/scenegraph/qsgopengldistancefieldglyphcache.cpp +++ b/src/quick/scenegraph/qsgopengldistancefieldglyphcache.cpp @@ -122,7 +122,7 @@ void QSGOpenGLDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs // We need to add a buffer to avoid glyphs that overlap the border between two // textures causing the height of the textures to extend beyond the limit. - m_maxTextureHeight = m_maxTextureWidth - (qCeil(m_referenceFont.pixelSize() * scaleFactor) + distanceFieldRadius() * 2 + padding * 2); + m_maxTextureHeight = m_maxTextureWidth - (qCeil(m_referenceFont.pixelSize() * scaleFactor + distanceFieldRadius() * 2) + padding * 2); } if (m_areaAllocator == nullptr) @@ -132,8 +132,8 @@ void QSGOpenGLDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs glyph_t glyphIndex = *it; QRectF boundingRect = glyphData(glyphIndex).boundingRect; - int glyphWidth = qCeil(boundingRect.width()) + distanceFieldRadius() * 2; - int glyphHeight = qCeil(boundingRect.height()) + distanceFieldRadius() * 2; + int glyphWidth = qCeil(boundingRect.width() + distanceFieldRadius()) * 2; + int glyphHeight = qCeil(boundingRect.height() + distanceFieldRadius()) * 2; QSize glyphSize(glyphWidth + padding * 2, glyphHeight + padding * 2); QRect alloc = m_areaAllocator->allocate(glyphSize); @@ -144,8 +144,8 @@ void QSGOpenGLDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs TexCoord unusedCoord = glyphTexCoord(unusedGlyph); QRectF unusedGlyphBoundingRect = glyphData(unusedGlyph).boundingRect; - int unusedGlyphWidth = qCeil(unusedGlyphBoundingRect.width()) + distanceFieldRadius() * 2; - int unusedGlyphHeight = qCeil(unusedGlyphBoundingRect.height()) + distanceFieldRadius() * 2; + int unusedGlyphWidth = qCeil(unusedGlyphBoundingRect.width() + distanceFieldRadius()) * 2; + int unusedGlyphHeight = qCeil(unusedGlyphBoundingRect.height() + distanceFieldRadius()) * 2; m_areaAllocator->deallocate(QRect(unusedCoord.x - padding, unusedCoord.y - padding, padding * 2 + unusedGlyphWidth, diff --git a/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp index 53b6fe117f..eb4db0f85e 100644 --- a/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp +++ b/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp @@ -86,8 +86,8 @@ void QSGRhiDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs) int padding = QSG_RHI_DISTANCEFIELD_GLYPH_CACHE_PADDING; QRectF boundingRect = glyphData(glyphIndex).boundingRect; - int glyphWidth = qCeil(boundingRect.width()) + distanceFieldRadius() * 2; - int glyphHeight = qCeil(boundingRect.height()) + distanceFieldRadius() * 2; + int glyphWidth = qCeil(boundingRect.width() + distanceFieldRadius() * 2); + int glyphHeight = qCeil(boundingRect.height() + distanceFieldRadius() * 2); QSize glyphSize(glyphWidth + padding * 2, glyphHeight + padding * 2); QRect alloc = m_areaAllocator->allocate(glyphSize); @@ -98,8 +98,8 @@ void QSGRhiDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs) TexCoord unusedCoord = glyphTexCoord(unusedGlyph); QRectF unusedGlyphBoundingRect = glyphData(unusedGlyph).boundingRect; - int unusedGlyphWidth = qCeil(unusedGlyphBoundingRect.width()) + distanceFieldRadius() * 2; - int unusedGlyphHeight = qCeil(unusedGlyphBoundingRect.height()) + distanceFieldRadius() * 2; + int unusedGlyphWidth = qCeil(unusedGlyphBoundingRect.width() + distanceFieldRadius() * 2); + int unusedGlyphHeight = qCeil(unusedGlyphBoundingRect.height() + distanceFieldRadius() * 2); m_areaAllocator->deallocate(QRect(unusedCoord.x - padding, unusedCoord.y - padding, padding * 2 + unusedGlyphWidth, diff --git a/src/quick/scenegraph/shaders/outlinedtext.vert b/src/quick/scenegraph/shaders/outlinedtext.vert index 9df832de3c..42fa577063 100644 --- a/src/quick/scenegraph/shaders/outlinedtext.vert +++ b/src/quick/scenegraph/shaders/outlinedtext.vert @@ -1,4 +1,5 @@ -uniform highp mat4 matrix; +uniform highp mat4 modelViewMatrix; +uniform highp mat4 projectionMatrix; uniform highp vec2 textureScale; uniform highp vec2 shift; uniform highp float dpr; @@ -19,6 +20,6 @@ void main() sCoordDown = (tCoord - vec2(0.0, 1.0)) * textureScale; sCoordLeft = (tCoord - vec2(-1.0, 0.0)) * textureScale; sCoordRight = (tCoord - vec2(1.0, 0.0)) * textureScale; - vec3 dprSnapPos = floor(vCoord.xyz * dpr + 0.5) / dpr; - gl_Position = matrix * vec4(dprSnapPos, vCoord.w); -}
\ No newline at end of file + vec4 xformed = modelViewMatrix * vCoord; + gl_Position = projectionMatrix * vec4(floor(xformed.xyz * dpr + 0.5) / dpr, xformed.w); +} diff --git a/src/quick/scenegraph/shaders/outlinedtext_core.vert b/src/quick/scenegraph/shaders/outlinedtext_core.vert index a854355460..50a1371e89 100644 --- a/src/quick/scenegraph/shaders/outlinedtext_core.vert +++ b/src/quick/scenegraph/shaders/outlinedtext_core.vert @@ -9,7 +9,8 @@ out vec2 sCoordDown; out vec2 sCoordLeft; out vec2 sCoordRight; -uniform mat4 matrix; +uniform mat4 modelViewMatrix; +uniform mat4 projectionMatrix; uniform vec2 textureScale; uniform vec2 shift; uniform float dpr; @@ -21,6 +22,6 @@ void main() sCoordDown = (tCoord - vec2(0.0, 1.0)) * textureScale; sCoordLeft = (tCoord - vec2(-1.0, 0.0)) * textureScale; sCoordRight = (tCoord - vec2(1.0, 0.0)) * textureScale; - vec3 dprSnapPos = floor(vCoord.xyz * dpr + 0.5) / dpr; - gl_Position = matrix * vec4(dprSnapPos, vCoord.w); -}
\ No newline at end of file + vec4 xformed = modelViewMatrix * vCoord; + gl_Position = projectionMatrix * vec4(floor(xformed.xyz * dpr + 0.5) / dpr, xformed.w); +} diff --git a/src/quick/scenegraph/shaders/styledtext.vert b/src/quick/scenegraph/shaders/styledtext.vert index 29c9902609..dc87dadd5f 100644 --- a/src/quick/scenegraph/shaders/styledtext.vert +++ b/src/quick/scenegraph/shaders/styledtext.vert @@ -1,4 +1,5 @@ -uniform highp mat4 matrix; +uniform highp mat4 modelViewMatrix; +uniform highp mat4 projectionMatrix; uniform highp vec2 textureScale; uniform highp vec2 shift; uniform highp float dpr; @@ -13,6 +14,6 @@ void main() { sampleCoord = tCoord * textureScale; shiftedSampleCoord = (tCoord - shift) * textureScale; - vec3 dprSnapPos = floor(vCoord.xyz * dpr + 0.5) / dpr; - gl_Position = matrix * vec4(dprSnapPos, vCoord.w); + vec4 xformed = modelViewMatrix * vCoord; + gl_Position = projectionMatrix * vec4(floor(xformed.xyz * dpr + 0.5) / dpr, xformed.w); } diff --git a/src/quick/scenegraph/shaders/styledtext_core.vert b/src/quick/scenegraph/shaders/styledtext_core.vert index 04a0e88da8..d9a81bf06f 100644 --- a/src/quick/scenegraph/shaders/styledtext_core.vert +++ b/src/quick/scenegraph/shaders/styledtext_core.vert @@ -6,7 +6,8 @@ in vec2 tCoord; out vec2 sampleCoord; out vec2 shiftedSampleCoord; -uniform mat4 matrix; +uniform mat4 modelViewMatrix; +uniform mat4 projectionMatrix; uniform vec2 textureScale; uniform vec2 shift; uniform float dpr; @@ -15,6 +16,6 @@ void main() { sampleCoord = tCoord * textureScale; shiftedSampleCoord = (tCoord - shift) * textureScale; - vec3 dprSnapPos = floor(vCoord.xyz * dpr + 0.5) / dpr; - gl_Position = matrix * vec4(dprSnapPos, vCoord.w); + vec4 xformed = modelViewMatrix * vCoord; + gl_Position = projectionMatrix * vec4(floor(xformed.xyz * dpr + 0.5) / dpr, xformed.w); } diff --git a/src/quick/scenegraph/shaders/textmask.vert b/src/quick/scenegraph/shaders/textmask.vert index 1692159d2c..7f418b0895 100644 --- a/src/quick/scenegraph/shaders/textmask.vert +++ b/src/quick/scenegraph/shaders/textmask.vert @@ -1,4 +1,5 @@ -uniform highp mat4 matrix; +uniform highp mat4 modelViewMatrix; +uniform highp mat4 projectionMatrix; uniform highp vec2 textureScale; uniform highp float dpr; @@ -10,6 +11,6 @@ varying highp vec2 sampleCoord; void main() { sampleCoord = tCoord * textureScale; - vec3 dprSnapPos = floor(vCoord.xyz * dpr + 0.5) / dpr; - gl_Position = matrix * vec4(dprSnapPos, vCoord.w); + vec4 xformed = modelViewMatrix * vCoord; + gl_Position = projectionMatrix * vec4(floor(xformed.xyz * dpr + 0.5) / dpr, xformed.w); } diff --git a/src/quick/scenegraph/shaders/textmask_core.vert b/src/quick/scenegraph/shaders/textmask_core.vert index b0efc1e731..1f88974aed 100644 --- a/src/quick/scenegraph/shaders/textmask_core.vert +++ b/src/quick/scenegraph/shaders/textmask_core.vert @@ -5,13 +5,14 @@ in vec2 tCoord; out vec2 sampleCoord; -uniform mat4 matrix; +uniform mat4 modelViewMatrix; +uniform mat4 projectionMatrix; uniform vec2 textureScale; uniform float dpr; void main() { sampleCoord = tCoord * textureScale; - vec3 dprSnapPos = floor(vCoord.xyz * dpr + 0.5) / dpr; - gl_Position = matrix * vec4(dprSnapPos, vCoord.w); + vec4 xformed = modelViewMatrix * vCoord; + gl_Position = projectionMatrix * vec4(floor(xformed.xyz * dpr + 0.5) / dpr, xformed.w); } diff --git a/src/quick/util/qquicktimeline.cpp b/src/quick/util/qquicktimeline.cpp index 7ec7c827eb..abe6eb7261 100644 --- a/src/quick/util/qquicktimeline.cpp +++ b/src/quick/util/qquicktimeline.cpp @@ -53,6 +53,8 @@ QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcTl, "qt.quick.timeline") + struct Update { Update(QQuickTimeLineValue *_g, qreal _v) : g(_g), v(_v) {} @@ -513,6 +515,7 @@ void QQuickTimeLine::reset(QQuickTimeLineValue &timeLineValue) qWarning() << "QQuickTimeLine: Cannot reset a QQuickTimeLineValue owned by another timeline."; return; } + qCDebug(lcTl) << static_cast<QObject*>(this) << timeLineValue.value(); remove(&timeLineValue); timeLineValue._t = nullptr; } diff --git a/src/quickshapes/qquickshape.cpp b/src/quickshapes/qquickshape.cpp index 8f2ef3cfc1..bdfd5e3f76 100644 --- a/src/quickshapes/qquickshape.cpp +++ b/src/quickshapes/qquickshape.cpp @@ -763,6 +763,13 @@ void QQuickShape::setAsynchronous(bool async) performance. Setting the value to \c true is safe in any case since rendering falls back to the default method when the vendor-specific approach, such as \c GL_NV_path_rendering, is not supported at run time. + + \deprecated + + Changing the default value (false) is not recommended. In particular, + support for Shape.NvprRenderer will not be available in future Qt versions. + Applications experiencing rendering problems with the property set to true + are advised to set it to false. */ bool QQuickShape::vendorExtensionsEnabled() const |