Merge remote-tracking branch 'origin/5.13' into dev
Conflicts: src/qml/jsruntime/qv4value_p.h src/qml/qml/qqmlmetatype.cpp src/qml/qml/qqmltypewrapper.cpp src/quick/items/qquicktableview.cpp Change-Id: I684f8e01a711580512848bf1253f39b39fcbf4c7
This commit is contained in:
commit
10e3b24c02
|
@ -1073,6 +1073,7 @@ bool Codegen::visit(Expression *ast)
|
|||
TailCallBlocker blockTailCalls(this);
|
||||
statement(ast->left);
|
||||
blockTailCalls.unblock();
|
||||
clearExprResultName(); // The name only holds for the left part
|
||||
accept(ast->right);
|
||||
return false;
|
||||
}
|
||||
|
@ -2537,7 +2538,7 @@ bool Codegen::visit(ObjectPattern *ast)
|
|||
|
||||
{
|
||||
RegisterScope innerScope(this);
|
||||
Reference value = expression(p->initializer);
|
||||
Reference value = expression(p->initializer, name);
|
||||
if (hasError)
|
||||
return false;
|
||||
value.loadInAccumulator();
|
||||
|
@ -2979,7 +2980,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
|
|||
// already defined
|
||||
return leaveContext();
|
||||
|
||||
_context->name = name;
|
||||
_context->name = name.isEmpty() ? currentExpr().result().name : name;
|
||||
_module->functions.append(_context);
|
||||
_context->functionIndex = _module->functions.count() - 1;
|
||||
|
||||
|
|
|
@ -199,8 +199,9 @@ public:
|
|||
codegen = cg;
|
||||
}
|
||||
|
||||
Reference() :
|
||||
Reference(const QString &name = QString()) :
|
||||
constant(0),
|
||||
name(name),
|
||||
isArgOrEval(false),
|
||||
isReadonly(false),
|
||||
isReferenceToConst(false),
|
||||
|
@ -418,6 +419,11 @@ protected:
|
|||
bool _trueBlockFollowsCondition = false;
|
||||
|
||||
public:
|
||||
explicit Result(const QString &name)
|
||||
: _result(name)
|
||||
, _requested(ex)
|
||||
{}
|
||||
|
||||
explicit Result(const Reference &lrvalue)
|
||||
: _result(lrvalue)
|
||||
, _requested(ex)
|
||||
|
@ -476,6 +482,10 @@ protected:
|
|||
void setResult(Reference &&result) {
|
||||
_result = std::move(result);
|
||||
}
|
||||
|
||||
void clearResultName() {
|
||||
_result.name.clear();
|
||||
}
|
||||
};
|
||||
|
||||
void enterContext(AST::Node *node);
|
||||
|
@ -523,12 +533,12 @@ protected:
|
|||
const BytecodeGenerator::Label *iffalse,
|
||||
bool trueBlockFollowsCondition);
|
||||
|
||||
inline Reference expression(AST::ExpressionNode *ast)
|
||||
inline Reference expression(AST::ExpressionNode *ast, const QString &name = QString())
|
||||
{
|
||||
if (!ast || hasError)
|
||||
return Reference();
|
||||
|
||||
pushExpr();
|
||||
pushExpr(name);
|
||||
ast->accept(this);
|
||||
return popResult();
|
||||
}
|
||||
|
@ -716,6 +726,7 @@ protected:
|
|||
inline void setExprResult(const Reference &result) { m_expressions.back().setResult(result); }
|
||||
inline void setExprResult(Reference &&result) { m_expressions.back().setResult(std::move(result)); }
|
||||
inline Reference exprResult() const { return m_expressions.back().result(); }
|
||||
inline void clearExprResultName() { m_expressions.back().clearResultName(); }
|
||||
|
||||
inline bool exprAccept(Format f) { return m_expressions.back().accept(f); }
|
||||
|
||||
|
@ -723,7 +734,7 @@ protected:
|
|||
|
||||
inline void pushExpr(Result &&expr) { m_expressions.push_back(std::move(expr)); }
|
||||
inline void pushExpr(const Result &expr) { m_expressions.push_back(expr); }
|
||||
inline void pushExpr() { m_expressions.emplace_back(); }
|
||||
inline void pushExpr(const QString &name = QString()) { m_expressions.emplace_back(name); }
|
||||
|
||||
inline Result popExpr()
|
||||
{
|
||||
|
|
|
@ -17,7 +17,7 @@ function createSpriteObjects() {
|
|||
|
||||
//![local]
|
||||
component = Qt.createComponent("Sprite.qml");
|
||||
sprite = component.createObject(appWindow, {"x": 100, "y": 100});
|
||||
sprite = component.createObject(appWindow, {x: 100, y: 100});
|
||||
|
||||
if (sprite == null) {
|
||||
// Error Handling
|
||||
|
@ -32,7 +32,7 @@ function createSpriteObjects() {
|
|||
//![finishCreation]
|
||||
function finishCreation() {
|
||||
if (component.status == Component.Ready) {
|
||||
sprite = component.createObject(appWindow, {"x": 100, "y": 100});
|
||||
sprite = component.createObject(appWindow, {x: 100, y: 100});
|
||||
if (sprite == null) {
|
||||
// Error Handling
|
||||
console.log("Error creating object");
|
||||
|
|
|
@ -77,8 +77,13 @@ ReturnedValue Lookup::resolvePrimitiveGetter(ExecutionEngine *engine, const Valu
|
|||
primitiveLookup.type = object.type();
|
||||
switch (primitiveLookup.type) {
|
||||
case Value::Undefined_Type:
|
||||
case Value::Null_Type:
|
||||
return engine->throwTypeError();
|
||||
case Value::Null_Type: {
|
||||
Scope scope(engine);
|
||||
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
|
||||
const QString message = QStringLiteral("Cannot read property '%1' of %2").arg(name->toQString())
|
||||
.arg(QLatin1String(primitiveLookup.type == Value::Undefined_Type ? "undefined" : "null"));
|
||||
return engine->throwTypeError(message);
|
||||
}
|
||||
case Value::Boolean_Type:
|
||||
primitiveLookup.proto = engine->booleanPrototype()->d();
|
||||
break;
|
||||
|
|
|
@ -120,7 +120,7 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
|
|||
} indexedLookup;
|
||||
struct {
|
||||
Heap::InternalClass *ic;
|
||||
Heap::QObjectWrapper *staticQObject;
|
||||
Heap::InternalClass *qmlTypeIc; // only used when lookup goes through QQmlTypeWrapper
|
||||
QQmlPropertyCache *propertyCache;
|
||||
QQmlPropertyData *propertyData;
|
||||
} qobjectLookup;
|
||||
|
|
|
@ -292,7 +292,6 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
|
|||
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.staticQObject = nullptr;
|
||||
lookup->qobjectLookup.propertyCache = ddata->propertyCache;
|
||||
lookup->qobjectLookup.propertyCache->addref();
|
||||
lookup->qobjectLookup.propertyData = propertyData;
|
||||
|
@ -325,7 +324,6 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
|
|||
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.staticQObject = nullptr;
|
||||
lookup->qobjectLookup.propertyCache = ddata->propertyCache;
|
||||
lookup->qobjectLookup.propertyCache->addref();
|
||||
lookup->qobjectLookup.propertyData = propertyData;
|
||||
|
|
|
@ -872,7 +872,6 @@ ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, E
|
|||
}
|
||||
|
||||
lookup->qobjectLookup.ic = This->internalClass();
|
||||
lookup->qobjectLookup.staticQObject = nullptr;
|
||||
lookup->qobjectLookup.propertyCache = ddata->propertyCache;
|
||||
lookup->qobjectLookup.propertyCache->addref();
|
||||
lookup->qobjectLookup.propertyData = property;
|
||||
|
|
|
@ -231,8 +231,7 @@ inline ReturnedValue QObjectWrapper::lookupGetterImpl(Lookup *lookup, ExecutionE
|
|||
if (!o || o->internalClass != lookup->qobjectLookup.ic)
|
||||
return revertLookup();
|
||||
|
||||
const Heap::QObjectWrapper *This = lookup->qobjectLookup.staticQObject ? lookup->qobjectLookup.staticQObject :
|
||||
static_cast<const Heap::QObjectWrapper *>(o);
|
||||
const Heap::QObjectWrapper *This = static_cast<const Heap::QObjectWrapper *>(o);
|
||||
QObject *qobj = This->object();
|
||||
if (QQmlData::wasDeleted(qobj))
|
||||
return QV4::Encode::undefined();
|
||||
|
|
|
@ -87,12 +87,29 @@ struct Q_QML_PRIVATE_EXPORT Value : public StaticValue
|
|||
QML_NEARLY_ALWAYS_INLINE HeapBasePtr m() const
|
||||
{
|
||||
HeapBasePtr b;
|
||||
#ifdef __ia64
|
||||
// Restore bits 49-47 to bits 63-61, undoing the workaround explained in
|
||||
// setM below.
|
||||
quint64 _tmp;
|
||||
|
||||
_tmp = _val & (7L << 47); // 0x3800000000000
|
||||
_tmp = (_tmp << 14) | (_val ^ _tmp);
|
||||
memcpy(&b, &_tmp, 8);
|
||||
#else
|
||||
memcpy(&b, &_val, 8);
|
||||
#endif
|
||||
return b;
|
||||
}
|
||||
QML_NEARLY_ALWAYS_INLINE void setM(HeapBasePtr b)
|
||||
{
|
||||
memcpy(&_val, &b, 8);
|
||||
#ifdef __ia64
|
||||
// On ia64, bits 63-61 in a 64-bit pointer are used to store the virtual region
|
||||
// number. Since this implementation is not 64-bit clean, we move bits 63-61
|
||||
// to bits 49-47 and hope for the best. This is undone in *m(), above.
|
||||
_val |= ((_val & (7L << 61)) >> 14);
|
||||
_val &= ((1L << 50)-1);
|
||||
#endif
|
||||
}
|
||||
#elif QT_POINTER_SIZE == 4
|
||||
QML_NEARLY_ALWAYS_INLINE HeapBasePtr m() const
|
||||
|
|
|
@ -1110,6 +1110,23 @@ UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T
|
|||
} break;
|
||||
./
|
||||
|
||||
UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_AUTOMATIC_SEMICOLON;
|
||||
UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_SEMICOLON;
|
||||
/.
|
||||
case $rule_number: {
|
||||
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7));
|
||||
node->isReadonlyMember = true;
|
||||
node->readonlyToken = loc(1);
|
||||
node->typeModifier = stringRef(3);
|
||||
node->propertyToken = loc(2);
|
||||
node->typeModifierToken = loc(3);
|
||||
node->typeToken = loc(5);
|
||||
node->identifierToken = loc(7);
|
||||
node->semicolonToken = loc(8);
|
||||
sym(1).Node = node;
|
||||
} break;
|
||||
./
|
||||
|
||||
UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_AUTOMATIC_SEMICOLON;
|
||||
UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_SEMICOLON;
|
||||
/.
|
||||
|
@ -1221,6 +1238,34 @@ UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T
|
|||
} break;
|
||||
./
|
||||
|
||||
UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET;
|
||||
/.
|
||||
case $rule_number: {
|
||||
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7));
|
||||
node->isReadonlyMember = true;
|
||||
node->readonlyToken = loc(1);
|
||||
node->typeModifier = stringRef(3);
|
||||
node->propertyToken = loc(2);
|
||||
node->typeModifierToken = loc(3);
|
||||
node->typeToken = loc(5);
|
||||
node->identifierToken = loc(7);
|
||||
node->semicolonToken = loc(8); // insert a fake ';' before ':'
|
||||
|
||||
AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(7));
|
||||
propertyName->identifierToken = loc(7);
|
||||
propertyName->next = 0;
|
||||
|
||||
AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding(propertyName, sym(10).UiArrayMemberList->finish());
|
||||
binding->colonToken = loc(8);
|
||||
binding->lbracketToken = loc(9);
|
||||
binding->rbracketToken = loc(11);
|
||||
|
||||
node->binding = binding;
|
||||
|
||||
sym(1).Node = node;
|
||||
} break;
|
||||
./
|
||||
|
||||
UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer;
|
||||
/.
|
||||
case $rule_number: {
|
||||
|
@ -1773,10 +1818,6 @@ PropertyDefinition: PropertyName T_COLON AssignmentExpression_In;
|
|||
/.
|
||||
case $rule_number: {
|
||||
AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, sym(3).Expression);
|
||||
if (auto *f = asAnonymousFunctionDefinition(sym(3).Expression)) {
|
||||
if (!AST::cast<AST::ComputedPropertyName *>(sym(1).PropertyName))
|
||||
f->name = driver->newStringRef(sym(1).PropertyName->asString());
|
||||
}
|
||||
if (auto *c = asAnonymousClassDefinition(sym(3).Expression)) {
|
||||
if (!AST::cast<AST::ComputedPropertyName *>(sym(1).PropertyName))
|
||||
c->name = driver->newStringRef(sym(1).PropertyName->asString());
|
||||
|
|
|
@ -608,9 +608,12 @@ Q_QML_EXPORT void qmlRegisterModule(const char *uri, int versionMajor, int versi
|
|||
template<typename T>
|
||||
QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true)
|
||||
{
|
||||
QObject *mutableObj = const_cast<QObject *>(obj);
|
||||
return qmlAttachedPropertiesObject(
|
||||
mutableObj, qmlAttachedPropertiesFunction(mutableObj, &T::staticMetaObject), create);
|
||||
// We don't need a concrete object to resolve the function. As T is a C++ type, it and all its
|
||||
// super types should be registered as CppType (or not at all). We only need the object and its
|
||||
// QML engine to resolve composite types. Therefore, the function is actually a static property
|
||||
// of the C++ type system and we can cache it here for improved performance on further lookups.
|
||||
static const auto func = qmlAttachedPropertiesFunction(nullptr, &T::staticMetaObject);
|
||||
return qmlAttachedPropertiesObject(const_cast<QObject *>(obj), func, create);
|
||||
}
|
||||
|
||||
inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName,
|
||||
|
|
|
@ -76,7 +76,7 @@ void QQmlApplicationEnginePrivate::init()
|
|||
&QCoreApplication::exit, Qt::QueuedConnection);
|
||||
#if QT_CONFIG(translation)
|
||||
QTranslator* qtTranslator = new QTranslator;
|
||||
if (qtTranslator->load(QLocale(), QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
|
||||
if (qtTranslator->load(QLocale(), QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath), QLatin1String(".qm")))
|
||||
QCoreApplication::installTranslator(qtTranslator);
|
||||
translators << qtTranslator;
|
||||
#endif
|
||||
|
@ -90,10 +90,10 @@ void QQmlApplicationEnginePrivate::loadTranslations(const QUrl &rootFile)
|
|||
if (rootFile.scheme() != QLatin1String("file") && rootFile.scheme() != QLatin1String("qrc"))
|
||||
return;
|
||||
|
||||
QFileInfo fi(rootFile.toLocalFile());
|
||||
QFileInfo fi(QQmlFile::urlToLocalFileOrQrc(rootFile));
|
||||
|
||||
QTranslator *translator = new QTranslator;
|
||||
if (translator->load(QLocale(), QLatin1String("qml"), QLatin1String("_"), fi.path() + QLatin1String("/i18n"))) {
|
||||
if (translator->load(QLocale(), QLatin1String("qml"), QLatin1String("_"), fi.path() + QLatin1String("/i18n"), QLatin1String(".qm"))) {
|
||||
QCoreApplication::installTranslator(translator);
|
||||
translators << translator;
|
||||
} else {
|
||||
|
@ -180,6 +180,9 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c)
|
|||
\list
|
||||
\li Connecting Qt.quit() to QCoreApplication::quit()
|
||||
\li Automatically loads translation files from an i18n directory adjacent to the main QML file.
|
||||
\list
|
||||
\li Translation files must have "qml_" prefix e.g. qml_ja_JP.qm.
|
||||
\endlist
|
||||
\li Automatically sets an incubation controller if the scene contains a QQuickWindow.
|
||||
\li Automatically sets a \c QQmlFileSelector as the url interceptor, applying file selectors to all
|
||||
QML files and assets.
|
||||
|
|
|
@ -1206,7 +1206,7 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
|
|||
\js
|
||||
var component = Qt.createComponent("Button.qml");
|
||||
if (component.status == Component.Ready)
|
||||
component.createObject(parent, {"x": 100, "y": 100});
|
||||
component.createObject(parent, {x: 100, y: 100});
|
||||
\endjs
|
||||
|
||||
Dynamically created instances can be deleted with the \c destroy() method.
|
||||
|
|
|
@ -1193,7 +1193,8 @@ QQmlPropertyCache *QQmlMetaType::propertyCache(const QQmlType &type, int minorVe
|
|||
void QQmlMetaType::unregisterType(int typeIndex)
|
||||
{
|
||||
QQmlMetaTypeDataPtr data;
|
||||
if (const QQmlTypePrivate *d = data->types.value(typeIndex).priv()) {
|
||||
const QQmlType type = data->types.value(typeIndex);
|
||||
if (const QQmlTypePrivate *d = type.priv()) {
|
||||
removeQQmlTypePrivate(data->idToType, d);
|
||||
removeQQmlTypePrivate(data->nameToType, d);
|
||||
removeQQmlTypePrivate(data->urlToType, d);
|
||||
|
@ -1203,6 +1204,7 @@ void QQmlMetaType::unregisterType(int typeIndex)
|
|||
module->remove(d);
|
||||
data->clearPropertyCachesForMinorVersion(typeIndex);
|
||||
data->types[typeIndex] = QQmlType();
|
||||
data->undeletableTypes.remove(type);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -454,16 +454,16 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object,
|
|||
if (!includeEnums || !name->startsWithUpper()) {
|
||||
QQmlData *ddata = QQmlData::get(qobjectSingleton, false);
|
||||
if (ddata && ddata->propertyCache) {
|
||||
ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton)));
|
||||
QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext);
|
||||
if (property) {
|
||||
lookup->qobjectLookup.ic = This->internalClass();
|
||||
lookup->qobjectLookup.staticQObject = static_cast<Heap::QObjectWrapper *>(val->heapObject());
|
||||
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;
|
||||
lookup->getter = QV4::QObjectWrapper::lookupGetter;
|
||||
return lookup->getter(lookup, engine, *This);
|
||||
lookup->getter = QQmlTypeWrapper::lookupSingletonProperty;
|
||||
return lookup->getter(lookup, engine, *object);
|
||||
}
|
||||
// Fall through to base implementation
|
||||
}
|
||||
|
@ -485,6 +485,39 @@ bool QQmlTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine
|
|||
return Object::virtualResolveLookupSetter(object, engine, lookup, value);
|
||||
}
|
||||
|
||||
ReturnedValue QQmlTypeWrapper::lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &object)
|
||||
{
|
||||
const auto revertLookup = [l, engine, &object]() {
|
||||
l->qobjectLookup.propertyCache->release();
|
||||
l->qobjectLookup.propertyCache = nullptr;
|
||||
l->getter = Lookup::getterGeneric;
|
||||
return Lookup::getterGeneric(l, engine, object);
|
||||
};
|
||||
|
||||
// we can safely cast to a QV4::Object here. If object is something else,
|
||||
// the internal class won't match
|
||||
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
|
||||
if (!o || o->internalClass != l->qobjectLookup.qmlTypeIc)
|
||||
return revertLookup();
|
||||
|
||||
Heap::QQmlTypeWrapper *This = static_cast<Heap::QQmlTypeWrapper *>(o);
|
||||
|
||||
QQmlType type = This->type();
|
||||
if (!type.isValid())
|
||||
return revertLookup();
|
||||
|
||||
if (!type.isQObjectSingleton() && !type.isCompositeSingleton())
|
||||
return revertLookup();
|
||||
|
||||
QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine->qmlEngine());
|
||||
QObject *qobjectSingleton = e->singletonInstance<QObject *>(type);
|
||||
Q_ASSERT(qobjectSingleton);
|
||||
|
||||
Scope scope(engine);
|
||||
ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, qobjectSingleton));
|
||||
return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup);
|
||||
}
|
||||
|
||||
void Heap::QQmlScopedEnumWrapper::destroy()
|
||||
{
|
||||
QQmlType::derefHandle(typePrivate);
|
||||
|
|
|
@ -114,6 +114,8 @@ struct Q_QML_EXPORT QQmlTypeWrapper : Object
|
|||
static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup);
|
||||
static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value);
|
||||
|
||||
static ReturnedValue lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &base);
|
||||
|
||||
protected:
|
||||
static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
|
||||
static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver);
|
||||
|
|
|
@ -76,12 +76,24 @@ public:
|
|||
QString typeNamespace() const;
|
||||
void setTypeNamespace(const QString &s);
|
||||
|
||||
static void checkNonRelative(const char *item, const QString &typeName, const QString &fileName)
|
||||
{
|
||||
if (fileName.startsWith(QLatin1Char('/')) || fileName.contains(QLatin1Char(':'))) {
|
||||
qWarning() << item << typeName
|
||||
<< "is specified with non-relative URL" << fileName << "in a qmldir file."
|
||||
<< "URLs in qmldir files should be relative to the qmldir file's directory.";
|
||||
}
|
||||
}
|
||||
|
||||
struct Plugin
|
||||
{
|
||||
Plugin() {}
|
||||
|
||||
Plugin(const QString &name, const QString &path)
|
||||
: name(name), path(path) {}
|
||||
: name(name), path(path)
|
||||
{
|
||||
checkNonRelative("Plugin", name, path);
|
||||
}
|
||||
|
||||
QString name;
|
||||
QString path;
|
||||
|
@ -93,7 +105,10 @@ public:
|
|||
|
||||
Component(const QString &typeName, const QString &fileName, int majorVersion, int minorVersion)
|
||||
: typeName(typeName), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion),
|
||||
internal(false), singleton(false) {}
|
||||
internal(false), singleton(false)
|
||||
{
|
||||
checkNonRelative("Component", typeName, fileName);
|
||||
}
|
||||
|
||||
QString typeName;
|
||||
QString fileName;
|
||||
|
@ -108,7 +123,10 @@ public:
|
|||
Script() {}
|
||||
|
||||
Script(const QString &nameSpace, const QString &fileName, int majorVersion, int minorVersion)
|
||||
: nameSpace(nameSpace), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion) {}
|
||||
: nameSpace(nameSpace), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion)
|
||||
{
|
||||
checkNonRelative("Script", nameSpace, fileName);
|
||||
}
|
||||
|
||||
QString nameSpace;
|
||||
QString fileName;
|
||||
|
|
|
@ -31,72 +31,68 @@
|
|||
|
||||
\section1 Scene Graph Adaptations in Qt Quick
|
||||
|
||||
Originally Qt Quick always relied on OpenGL (OpenGL ES 2.0 or OpenGL 2.0) for parsing
|
||||
the scene graph and rendering the results to a render target. From Qt 5.8 onwards
|
||||
Qt Quick also supports rendering in software and with Direct3D 12.
|
||||
Originally, Qt Quick always relied on OpenGL (OpenGL ES 2.0 or OpenGL 2.0) to parse the scene graph
|
||||
and render the results to a render target. From Qt 5.8 onwards, Qt Quick also supports rendering in
|
||||
software and with Direct3D 12.
|
||||
|
||||
\section1 Switching Between the Adaptation Used by the Application
|
||||
\target Switching Between the Adaptation Used by the Application
|
||||
\section1 Switch Between Adaptations in Your Application
|
||||
|
||||
The default rendering backend is still OpenGL, or - in Qt builds with disabled OpenGL support -
|
||||
the software renderer. This can be overridden either by using an environment variable
|
||||
or a C++ API. The former consists of setting the \c{QT_QUICK_BACKEND} or the
|
||||
legacy \c{QMLSCENE_DEVICE} environment variable before launching applications.
|
||||
The latter is done by calling QQuickWindow::setSceneGraphBackend() early in the
|
||||
application's main() function.
|
||||
|
||||
The supported backends are the following
|
||||
The default rendering backend is still OpenGL, but in Qt builds with OpenGL support disabled, the
|
||||
default is the software renderer. You can override this in one of two ways:
|
||||
|
||||
\list
|
||||
|
||||
\li OpenGL - Requested by the string \c{""} or the enum value QSGRendererInterface::OpenGL.
|
||||
|
||||
\li Software - Requested by the string \c{"software"} or the enum value QSGRendererInterface::Software.
|
||||
|
||||
\li Direct3D 12 - Requested by the string \c{"d3d12"} or the enum value QSGRendererInterface::Direct3D12.
|
||||
|
||||
\li OpenVG - Requested by the string \c{"openvg"} or the enum value QSGRendererInterface::OpenVG.
|
||||
|
||||
\li Use an environment variable - Set the \c{QT_QUICK_BACKEND} or the legacy
|
||||
\c{QMLSCENE_DEVICE} environment variable before launching applications.
|
||||
\li Use a C++ API - Call QQuickWindow::setSceneGraphBackend() early on in the application's
|
||||
main() function.
|
||||
\endlist
|
||||
|
||||
When in doubt which backend is in use, enable basic scenegraph information
|
||||
logging via the \c{QSG_INFO} environment variable or the
|
||||
\c{qt.scenegraph.general} logging category. This will result in printing some
|
||||
information during application startup onto the debug output.
|
||||
The following backends are supported:
|
||||
|
||||
\note Adaptations other than OpenGL will typically come with a set of
|
||||
limitations since they are unlikely to provide a feature set 100% compatible
|
||||
with OpenGL. However, they may provide their own specific advantages in certain
|
||||
areas. Refer to the sections below for more information on the various
|
||||
adaptations.
|
||||
\list
|
||||
\li OpenGL - Request with the \c{""} string or the QSGRendererInterface::OpenGL enum value.
|
||||
\li Software - Request with the \c{"software"} string or the QSGRendererInterface::Software
|
||||
enum value.
|
||||
\li Direct3D 12 - Request with the \c{"d3d12"} string or the QSGRendererInterface::Direct3D12
|
||||
enum value.
|
||||
\li OpenVG - Request with the \c{"openvg"} string or the QSGRendererInterface::OpenVG enum
|
||||
value.
|
||||
\endlist
|
||||
|
||||
To find out which backend is in use, you can enable basic scene graph information logging via the
|
||||
\c{QSG_INFO} environment variable or the \c{qt.scenegraph.general} logging category. This results
|
||||
in some information being printed onto the debug output, during application startup.
|
||||
|
||||
\note Typically, adaptations other than OpenGL come with a set of limitations as they are unlikely
|
||||
to provide a feature set that's 100% compatible with OpenGL. However, these adaptations may
|
||||
provide their own specific advantages in certain areas. For more information on the various
|
||||
adaptations, refer to the sections below.
|
||||
|
||||
\section1 OpenGL ES 2.0 and OpenGL 2.0 Adaptation
|
||||
|
||||
The default adaptation capable of providing the full Qt Quick 2 feature
|
||||
set is the OpenGL adaptation. All of the details of the OpenGL
|
||||
adaptation can are available here:
|
||||
\l{qtquick-visualcanvas-scenegraph-renderer.html}{OpenGL Adaptation}
|
||||
The OpenGL adaptation is the default adaptation, which is capable of providing the full Qt Quick 2
|
||||
feature set. For more details, see
|
||||
\l{qtquick-visualcanvas-scenegraph-renderer.html}{OpenGL Adaptation}.
|
||||
|
||||
\section1 Software Adaptation
|
||||
|
||||
The Software adaptation is an alternative renderer for \l {Qt Quick} 2 that
|
||||
uses the raster paint engine to render the contents of the scene graph. The
|
||||
details for this adaptation are available here:
|
||||
\l{qtquick-visualcanvas-adaptations-software.html}{Software Adaptation}
|
||||
The Software adaptation is an alternative renderer for \l{Qt Quick} 2 that uses the raster paint
|
||||
engine to render the contents of the scene graph. For more details, see
|
||||
\l{qtquick-visualcanvas-adaptations-software.html}{Software Adaptation}.
|
||||
|
||||
\section1 Direct3D 12 (experimental)
|
||||
|
||||
The Direct3D 12 adaptation is an alternative renderer for \l {Qt Quick} 2 when
|
||||
running on Windows 10, both for Win32 and UWP applications. The details for
|
||||
this adaptation are available here:
|
||||
\l{qtquick-visualcanvas-adaptations-d3d12.html}{Direct3D 12 Adaptation}
|
||||
The Direct3D 12 adaptation is an alternative renderer for \l{Qt Quick} 2 when running on Windows
|
||||
10, both for Win32 and UWP applications. For more details, see
|
||||
\l{qtquick-visualcanvas-adaptations-d3d12.html}{Direct3D 12 Adaptation}.
|
||||
|
||||
\section1 OpenVG
|
||||
|
||||
The OpenVG adaptation is an alternative renderer for \l {Qt Quick} 2 that will
|
||||
renderer the contents of the scene graph using OpenVG commands to provide
|
||||
hardware-acclerated 2D vector and raster graphics. The details for this
|
||||
adaptation are available here:
|
||||
\l{qtquick-visualcanvas-adaptations-openvg.html}{OpenVG Adaptation}
|
||||
The OpenVG adaptation is an alternative renderer for \l{Qt Quick} 2 that renders the contents of
|
||||
the scene graph using OpenVG commands to provide hardware-accelerated 2D vector and raster
|
||||
graphics. For more details, see
|
||||
\l{qtquick-visualcanvas-adaptations-openvg.html}{OpenVG Adaptation}.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -104,47 +100,44 @@ adaptation are available here:
|
|||
\title Qt Quick Software Adaptation
|
||||
\page qtquick-visualcanvas-adaptations-software.html
|
||||
|
||||
The Software adaptation is an alternative renderer for \l {Qt Quick} 2 that
|
||||
uses the Raster paint engine to render the contents of the scene graph instead
|
||||
of OpenGL. As a result of not using OpenGL to render the scene graph, some
|
||||
features and optimizations are no longer available. Most Qt Quick 2
|
||||
applications will run without modification though any attempts to use
|
||||
unsupported features will be ignored. By using the Software adaptation it is
|
||||
possible to run Qt Quick 2 applications on hardware and platforms that do not
|
||||
have OpenGL support.
|
||||
The Software adaptation is an alternative renderer for \l {Qt Quick} 2 that uses the Raster paint
|
||||
engine to render the contents of the scene graph, instead of OpenGL. Consequently, some features
|
||||
and optimizations are not available. Most Qt Quick 2 applications can run without any modification,
|
||||
but any attempts to use unsupported features are ignored. By using the Software adaptation, it is
|
||||
possible to run Qt Quick 2 applications on hardware and platforms that do not have OpenGL support.
|
||||
|
||||
The Software adaptation was previously known as the Qt Quick 2D Renderer.
|
||||
However, unlike the 2D Renderer, the new, integrated version supports partial
|
||||
updates. This means that the full update of the window or screen contents is
|
||||
now avoided, and only the changed areas get flushed. This can significantly
|
||||
improve performance for many applications.
|
||||
The Software adaptation was previously known as the Qt Quick 2D Renderer. However, unlike the 2D
|
||||
Renderer, this new, integrated version supports partial updates. This means that a full update
|
||||
of the window or screen contents is now avoided; only the changed areas are flushed. Partial
|
||||
updates can significantly improve performance for many applications.
|
||||
|
||||
\section2 Shader Effects
|
||||
ShaderEffect components in QtQuick 2 can not be rendered by the Software adptation.
|
||||
|
||||
ShaderEffect components in QtQuick 2 cannot be rendered by the Software adaptation.
|
||||
|
||||
\section2 Qt Graphical Effects Module
|
||||
\l {Qt Graphical Effects} uses ShaderEffect items to render effects. If you use
|
||||
graphical effects from this module, then you should not hide the source
|
||||
item so that the original item can still be rendered.
|
||||
|
||||
\l {Qt Graphical Effects} uses ShaderEffect items to render effects. If you use graphical effects
|
||||
from this module, then you should not hide the source item so that the original item can still be
|
||||
rendered.
|
||||
|
||||
\section2 Particle Effects
|
||||
It is not possible to render particle effects with the Software adaptation. Whenever
|
||||
possible, remove particles completely from the scene. Otherwise they will still
|
||||
require some processing, even though they are not visible.
|
||||
|
||||
It is not possible to render particle effects with the Software adaptation. Whenever possible,
|
||||
remove particles completely from the scene. Otherwise, they will still require some processing,
|
||||
even though they are not visible.
|
||||
|
||||
\section2 Rendering Text
|
||||
The text rendering with the Software adaptation is based on software
|
||||
rasterization and does not respond as well to transformations such as scaling
|
||||
as when using OpenGL. The quality is similar to choosing \l [QML] {Text::renderType}
|
||||
{Text.NativeRendering} with \l [QML] {Text} items.
|
||||
|
||||
The text rendering with the Software adaptation is based on software rasterization and does not
|
||||
respond as well to transformations such as scaling, compared to when using OpenGL. The quality is
|
||||
similar to choosing \l [QML] {Text::renderType}{Text.NativeRendering} with \l [QML] {Text} items.
|
||||
|
||||
\section2 Qt Multimedia VideoOutput
|
||||
The VideoOutput item of the Qt Multimedia module is not supported with the software
|
||||
adaptation. This is because VideoOutput uses the QVideoRendererControl item which
|
||||
requires custom QSGGeometryNode behavior that is only present in the default OpenGL
|
||||
adaptation.
|
||||
|
||||
|
||||
The Qt Multimedia module's VideoOutput item is not supported with the Software adaptation. This
|
||||
is because VideoOutput uses the QVideoRendererControl item which requires custom QSGGeometryNode
|
||||
behavior, which is only present in the default OpenGL adaptation.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -152,251 +145,228 @@ adaptation.
|
|||
\title Qt Quick Direct3D 12 Adaptation
|
||||
\page qtquick-visualcanvas-adaptations-d3d12.html
|
||||
|
||||
The Direct3D 12 adaptation for Windows 10 (both Win32 (\c windows platform
|
||||
plugin) and UWP (\c winrt platform plugin)) is shipped as a dynamically loaded
|
||||
plugin. It will not be functional on earlier Windows versions. The building of
|
||||
the plugin is enabled automatically whenever the necessary D3D and DXGI
|
||||
develpoment files are present. In practice this currently means Visual Studio
|
||||
2015 and newer.
|
||||
The Direct3D 12 adaptation for Windows 10, both in Win32 (\c windows platform plugin) and in UWP
|
||||
(\c winrt platform plugin), is shipped as a dynamically loaded plugin. This adaptation doesn't work
|
||||
on earlier Windows versions. Building this plugin is enabled automatically, whenever the necessary
|
||||
D3D and DXGI develpoment files are present. In practice, this currently means Visual Studio 2015
|
||||
and newer.
|
||||
|
||||
The adaptation is available both in normal, OpenGL-enabled Qt builds and also
|
||||
when Qt was configured with \c{-no-opengl}. However, it is never the default,
|
||||
meaning the user or the application has to explicitly request it by setting the
|
||||
\c{QT_QUICK_BACKEND} environment variable to \c{d3d12} or by calling
|
||||
QQuickWindow::setSceneGraphBackend().
|
||||
The adaptation is available both in normal, OpenGL-enabled Qt builds, and also when Qt is
|
||||
configured with \c{-no-opengl}. However, it's never the default, meaning that the user or the
|
||||
application has to explicitly request it by setting the \c{QT_QUICK_BACKEND} environment variable
|
||||
to \c{d3d12} or by calling QQuickWindow::setSceneGraphBackend().
|
||||
|
||||
\section2 Motivation
|
||||
|
||||
This experimental adaptation is the first Qt Quick backend focusing on a
|
||||
modern, lower-level graphics API in combination with a windowing system
|
||||
interface different from the traditional approaches used in combination with
|
||||
OpenGL.
|
||||
This experimental adaptation is the first Qt Quick backend that focuses on a modern, lower-level
|
||||
graphics API in combination with a windowing system interface that's different from the traditional
|
||||
approaches used in combination with OpenGL.
|
||||
|
||||
It also allows better integration with Windows, Direct3D being the primary
|
||||
vendor-supported solution. This means that there are fewer problems anticipated
|
||||
with drivers, operations like window resizes, and special events like graphics
|
||||
device loss caused by device resets or graphics driver updates.
|
||||
This adaptation also allows better integration with Windows, as Direct3D is the primary
|
||||
vendor-supported solution. Consequently, there are fewer problems anticipated with drivers,
|
||||
operations like window resizes, and special events like graphics device loss caused by device
|
||||
resets or graphics driver updates.
|
||||
|
||||
Performance-wise the general expectation is a somewhat lower CPU usage compared
|
||||
to OpenGL due to lower driver overhead, and a higher GPU utilization with less
|
||||
wasted idle time. The backend does not heavily utilize threads yet, which means
|
||||
there are opportunities for further improvements in the future, for example to
|
||||
further optimize image loading.
|
||||
Performance-wise, the general expectation is a somewhat lower CPU usage compared to OpenGL, due to
|
||||
lower driver overhead, and a higher GPU utilization with less idle time wastage. The backend
|
||||
doesn't heavily utilize threads yet, which means there are opportunities for further improvements
|
||||
in the future, for example to further optimize image loading.
|
||||
|
||||
The D3D12 backend also introduces support for pre-compiled shaders. All the
|
||||
backend's own shaders (used by the built-in materials on which the Rectangle,
|
||||
Image, Text, etc. QML types are built) are compiled to D3D shader bytecode when
|
||||
compiling Qt. Applications using ShaderEffect items can chose to ship bytecode
|
||||
either in regular files or via the Qt resource system, or use HLSL source
|
||||
strings. Unlike OpenGL, the compilation for the latter is properly threaded,
|
||||
meaning shader compilation will not block the application and its user
|
||||
The D3D12 backend also introduces support for pre-compiled shaders. All the backend's own shaders
|
||||
(used by the built-in materials on which the Rectangle, Image, Text, and other QML types are built
|
||||
with) are compiled to D3D shader bytecode when you compile Qt. Applications using ShaderEffect
|
||||
items can choose to ship bytecode either in regular files, via the Qt resource system, or use
|
||||
High Level Shading Language for DirectX (HLSL) source strings. Unlike OpenGL, the compilation for
|
||||
HLSL is properly threaded, meaning shader compilation won't block the application and its user
|
||||
interface.
|
||||
|
||||
\section2 Graphics Adapters
|
||||
|
||||
The plugin does not necessarily require hardware acceleration. Using WARP, the
|
||||
Direct3D software rasterizer, is also an option. By default the first adapter
|
||||
providing hardware acceleration is chosen. To override this, in order to use
|
||||
another graphics adapter or to force the usage of the software rasterizer, set
|
||||
the environment variable \c{QT_D3D_ADAPTER_INDEX} to the index of the adapter.
|
||||
The discovered adapters are printed at startup when \c{QSG_INFO} or the logging
|
||||
category \c{qt.scenegraph.general} is enabled.
|
||||
The plugin does not necessarily require hardware acceleration. You can also use WARP, the Direct3D
|
||||
software rasterizer. By default, the first adapter providing hardware acceleration is chosen. To
|
||||
override this and use another graphics adapter or to force the use of the software rasterizer, set
|
||||
the \c{QT_D3D_ADAPTER_INDEX} environment variable to the index of the adapter. The adapters
|
||||
discovered are printed at startup when \c{QSG_INFO} or the \c{qt.scenegraph.general} logging
|
||||
category is enabled.
|
||||
|
||||
\section2 Troubleshooting
|
||||
|
||||
When encountering issues, always set the \c{QSG_INFO} and \c{QT_D3D_DEBUG}
|
||||
environment variables to 1 in order to get debug and warning messages printed
|
||||
on the debug output. The latter enables the Direct3D debug layer. Note that the
|
||||
debug layer should not be enabled in production use since it can significantly
|
||||
impact performance (CPU load) due to increased API overhead.
|
||||
If you encounter issues, always set the \c{QSG_INFO} and \c{QT_D3D_DEBUG} environment variables
|
||||
to \c 1, to get debug and warning messages printed on the debug output. \c{QT_D3D_DEBUG} enables
|
||||
the Direct3D debug layer.
|
||||
|
||||
\note The debug layer shouldn't be enabled in production use, since it can significantly impact
|
||||
performance (CPU load) due to increased API overhead.
|
||||
|
||||
\section2 Render Loops
|
||||
|
||||
By default the D3D12 adaptation uses a single-threaded render loop similar to
|
||||
OpenGL's \c windows render loop. There is also a threaded variant available, that
|
||||
can be requested by setting the \c{QSG_RENDER_LOOP} environment variable to \c
|
||||
threaded. However, due to conceptual limitations in DXGI, the windowing system
|
||||
interface, the threaded loop is prone to deadlocks when multiple QQuickWindow
|
||||
or QQuickView instances are shown. Therefore the default is the single-threaded
|
||||
loop for the time being. This means that with the D3D12 backend applications
|
||||
are expected to move their work from the main (GUI) thread out to worker
|
||||
threads, instead of expecting Qt to keep the GUI thread responsive and suitable
|
||||
for heavy, blocking operations.
|
||||
By default, the D3D12 adaptation uses a single-threaded render loop similar to OpenGL's \c windows
|
||||
render loop. A threaded variant is also available, that you can request by setting the
|
||||
\c{QSG_RENDER_LOOP} environment variable to \c threaded. However, due to conceptual limitations in
|
||||
DXGI, the windowing system interface, the threaded loop is prone to deadlocks when multiple
|
||||
QQuickWindow or QQuickView instances are shown. Consequently, for the time being, the default is
|
||||
the single-threaded loop. This means that with the D3D12 backend, applications are expected to move
|
||||
their work from the main (GUI) thread out to worker threads, instead of expecting Qt to keep the
|
||||
GUI thread responsive and suitable for heavy, blocking operations.
|
||||
|
||||
See the \l{qtquick-visualcanvas-scenegraph.html}{Scene Graph page} for more
|
||||
information on render loops and
|
||||
\l{https://msdn.microsoft.com/en-us/library/windows/desktop/ee417025(v=vs.85).aspx#multithreading_and_dxgi}{the
|
||||
MSDN page for DXGI} regarding the issues with multithreading.
|
||||
For more information see \l{qtquick-visualcanvas-scenegraph.html}{Qt Quick Scene Graph} for
|
||||
details on render loops and
|
||||
\l{https://docs.microsoft.com/en-us/windows/desktop/direct3darticles/dxgi-best-practices#multithreading-and-dxgi}{Multithreading and DXGI}
|
||||
regarding the issues with multithreading.
|
||||
|
||||
\section2 Renderer
|
||||
|
||||
The scenegraph renderer in the D3D12 adaptation does not currently perform any
|
||||
batching. This is less of an issue, unlike OpenGL, because state changes are
|
||||
not presenting any problems in the first place. The simpler renderer logic can
|
||||
also lead to lower CPU overhead in some cases. The trade-offs between the
|
||||
various approaches are currently under research.
|
||||
The scene graph renderer in the D3D12 adaptation currently doesn't perform any batching. This is
|
||||
less of an issue, unlike OpenGL, because state changes don't present any problems in the first
|
||||
place. The simpler renderer logic can also lead to lower CPU overhead in some cases. The trade-offs
|
||||
between the various approaches are currently under research.
|
||||
|
||||
\section2 Shader Effects
|
||||
|
||||
The ShaderEffect QML type is fully functional with the D3D12 adaptation as well.
|
||||
However, the interpretation of the fragmentShader and vertexShader properties is
|
||||
different than with OpenGL.
|
||||
The ShaderEffect QML type is fully functional with the D3D12 adaptation as well. However, the
|
||||
interpretation of the fragmentShader and vertexShader properties is different than with OpenGL.
|
||||
|
||||
With D3D12, these strings can either be an URL for a local file or a file in
|
||||
the resource system, or a HLSL source string. The former indicates that the
|
||||
file in question contains pre-compiled D3D shader bytecode generated by the
|
||||
\c fxc tool, or, alternatively, HLSL source code. The type of the file is detected
|
||||
automatically. This means that the D3D12 backend supports all options from
|
||||
GraphicsInfo.shaderCompilationType and GraphicsInfo.shaderSourceType.
|
||||
With D3D12, these strings can either be a URL for a local file, a file in the resource system,
|
||||
or an HLSL source string. Using a URL for a local file or a file in the resource system
|
||||
indicates that the file in question contains pre-compiled D3D shader bytecode generated by the
|
||||
\c fxc tool, or, alternatively, HLSL source code. The type of file is detected automatically.
|
||||
This means that the D3D12 backend supports all options from GraphicsInfo.shaderCompilationType
|
||||
and GraphicsInfo.shaderSourceType.
|
||||
|
||||
Unlike OpenGL, there is a QFileSelector with the extra selector \c hlsl used
|
||||
whenever opening a file. This allows easy creation of ShaderEffect items that
|
||||
are functional across both backends, for example by placing the GLSL source
|
||||
code into \c{shaders/effect.frag}, the HLSL source code or - preferably -
|
||||
pre-compiled bytecode into \c{shaders/+hlsl/effect.frag}, while simply writing
|
||||
\c{fragmentShader: "qrc:shaders/effect.frag"} in QML.
|
||||
|
||||
See the ShaderEffect documentation for more details.
|
||||
Unlike OpenGL, whenever you open a file, there is a QFileSelector with the extra \c hlsl selector
|
||||
used. This provides easy creation of ShaderEffect items that are functional across both backends,
|
||||
for example by placing the GLSL source code into \c{shaders/effect.frag}, the HLSL source code or
|
||||
- preferably - pre-compiled bytecode into \c{shaders/+hlsl/effect.frag}, while simply writing
|
||||
\c{fragmentShader: "qrc:shaders/effect.frag"} in QML. For more details, see ShaderEffect.
|
||||
|
||||
\section2 Multisample Render Targets
|
||||
|
||||
The Direct3D 12 adaptation ignores the QSurfaceFormat set on the QQuickWindow
|
||||
or QQuickView (or set via QSurfaceFormat::setDefaultFormat()), with two
|
||||
exceptions: QSurfaceFormat::samples() and QSurfaceFormat::alphaBufferSize() are
|
||||
still taken into account. When the samples value is greater than 1, multisample
|
||||
offscreen render targets will be created with the specified sample count and a
|
||||
quality of the maximum supported quality level. The backend automatically
|
||||
performs resolving into the non-multisample swapchain buffers after each frame.
|
||||
The Direct3D 12 adaptation ignores the QSurfaceFormat set on the QQuickWindow or QQuickView, or
|
||||
set via QSurfaceFormat::setDefaultFormat(), with two exceptions: QSurfaceFormat::samples() and
|
||||
QSurfaceFormat::alphaBufferSize() are still taken into account. When the sample value is greater
|
||||
than 1, multisample offscreen render targets will be created with the specified sample count at
|
||||
the maximum supported quality level. The backend automatically performs resolving into the
|
||||
non-multisample swapchain buffers after each frame.
|
||||
|
||||
\section2 Semi-transparent Windows
|
||||
|
||||
When the alpha channel is enabled either via
|
||||
QQuickWindow::setDefaultAlphaBuffer() or by setting alphaBufferSize to a
|
||||
non-zero value in the window's QSurfaceFormat or in the global format managed
|
||||
by QSurfaceFormat::setDefaultFormat(), the D3D12 backend will create a
|
||||
swapchain for composition and go through DirectComposition since the flip model
|
||||
swapchain (which is mandatory) would not support transparency otherwise.
|
||||
When the alpha channel is enabled either via QQuickWindow::setDefaultAlphaBuffer() or by setting
|
||||
alphaBufferSize to a non-zero value in the window's QSurfaceFormat or in the global format managed
|
||||
by QSurfaceFormat::setDefaultFormat(), the D3D12 backend will create a swapchain for composition
|
||||
and go through DirectComposition. This is necessary, because the mandatory flip model swapchain
|
||||
wouldn't support transparency otherwise.
|
||||
|
||||
It is therefore important not to unneccessarily request an alpha channel. When
|
||||
the alphaBufferSize is 0 or the default -1, all these extra steps can be
|
||||
avoided and the traditional window-based swapchain is sufficient.
|
||||
Therefore, it's important not to unneccessarily request an alpha channel. When the alphaBufferSize
|
||||
is 0 or the default -1, all these extra steps can be avoided and the traditional window-based
|
||||
swapchain is sufficient.
|
||||
|
||||
This is not relevant on WinRT because there the backend always uses a
|
||||
composition swapchain which is associated with the ISwapChainPanel that backs
|
||||
QWindow on that platform.
|
||||
On WinRT, this isn't relevant because the backend there always uses a composition swapchain which
|
||||
is associated with the ISwapChainPanel that backs QWindow on that platform.
|
||||
|
||||
\section2 Mipmaps
|
||||
|
||||
Mipmap generation is supported and handled transparently to the applications
|
||||
via a built-in compute shader, but is experimental and only supports
|
||||
power-of-two images at the moment. Textures of other size will work too, but
|
||||
this involves a QImage-based scaling on the CPU first. Therefore avoid enabling
|
||||
mipmapping for NPOT images whenever possible.
|
||||
Mipmap generation is supported and handled transparently to the applications via a built-in compute
|
||||
shader. However, at the moment, this feature is experimental and only supports power-of-two images.
|
||||
Textures of other size will work too, but this involves a QImage-based scaling on the CPU first.
|
||||
Therefore, avoid enabling mipmapping for Non-Power-Of-Two (NPOT) images whenever possible.
|
||||
|
||||
\section2 Image Formats
|
||||
|
||||
When creating textures via the C++ scenegraph APIs like
|
||||
QQuickWindow::createTextureFromImage(), 32-bit formats will not involve any
|
||||
conversion, they will map directly to the corresponding \c{R8G8B8A8_UNORM} or
|
||||
\c{B8G8R8A8_UNORM} format. Everything else will trigger a QImage-based format
|
||||
conversion on the CPU first.
|
||||
When creating textures via C++ scene graph APIs like QQuickWindow::createTextureFromImage(), 32-bit
|
||||
formats won't involve any conversion, they'll map directly to the corresponding \c{R8G8B8A8_UNORM}
|
||||
or \c{B8G8R8A8_UNORM} format. Everything else will trigger a QImage-based format conversion on the
|
||||
CPU first.
|
||||
|
||||
\section2 Unsupported Features
|
||||
|
||||
Particles and some other OpenGL-dependent utilities, like
|
||||
QQuickFramebufferObject, are not currently supported.
|
||||
Particles and some other OpenGL-dependent utilities, like QQuickFramebufferObject, are currently
|
||||
not supported.
|
||||
|
||||
Like with the \l{qtquick-visualcanvas-adaptations-software.html}{Software
|
||||
adaptation}, text is always rendered using the native method. Distance
|
||||
field-based text rendering is not currently implemented.
|
||||
Like with \l{qtquick-visualcanvas-adaptations-software.html}{Software adaptation}, text is always
|
||||
rendered using the native method. Distance field-based text rendering is currently not implemented.
|
||||
|
||||
The shader sources in the \l {Qt Graphical Effects} module have not been ported
|
||||
to any format other than the OpenGL 2.0 compatible one, meaning the QML types
|
||||
provided by that module are not currently functional with the D3D12 backend.
|
||||
The shader sources in the \l {Qt Graphical Effects} module have not been ported to any format other
|
||||
than the OpenGL 2.0 compatible one, meaning that the QML types provided by that module are currently
|
||||
not functional with the D3D12 backend.
|
||||
|
||||
Texture atlases are not currently in use.
|
||||
Texture atlases are currently not in use.
|
||||
|
||||
The renderer may lack support for certain minor features, for example drawing
|
||||
points and lines with a width other than 1.
|
||||
The renderer may lack support for certain minor features, such as drawing points and lines with a
|
||||
width other than 1.
|
||||
|
||||
Custom Qt Quick items using custom scenegraph nodes can be problematic.
|
||||
Materials are inherently tied to the graphics API. Therefore only items using
|
||||
the utility rectangle and image nodes are functional across all adaptations.
|
||||
Custom Qt Quick items using custom scene graph nodes can be problematic because materials are
|
||||
inherently tied to the graphics API. Therefore, only items that use the utility rectangle and image
|
||||
nodes are functional across all adaptations.
|
||||
|
||||
QQuickWidget and its underlying OpenGL-based compositing architecture is not
|
||||
supported. If mixing with QWidget-based user interfaces is desired, use
|
||||
QWidget::createWindowContainer() to embed the native window of the QQuickWindow
|
||||
or QQuickView.
|
||||
QQuickWidget and its underlying OpenGL-based compositing architecture is not supported. If you need
|
||||
to mix with QWidget-based user interfaces, use QWidget::createWindowContainer() to embed the native
|
||||
window of the QQuickWindow or QQuickView.
|
||||
|
||||
Finally, rendering via QSGEngine and QSGAbstractRenderer is not feasible with
|
||||
the D3D12 adaptation at the moment.
|
||||
Finally, rendering via QSGEngine and QSGAbstractRenderer is not feasible with the D3D12 adaptation
|
||||
at the moment.
|
||||
|
||||
\section2 Related APIs
|
||||
|
||||
To integrate custom Direct3D 12 rendering, use QSGRenderNode in combination
|
||||
with QSGRendererInterface. This approach does not rely on OpenGL contexts or
|
||||
API specifics like framebuffers, and allows exposing the graphics device and
|
||||
command buffer from the adaptation. It is not necessarily suitable for easy
|
||||
integration of all types of content, in particular true 3D, so it will likely
|
||||
get complemented by an alternative to QQuickFramebufferObject in future
|
||||
releases.
|
||||
To integrate custom Direct3D 12 rendering, use QSGRenderNode in combination with
|
||||
QSGRendererInterface. This approach doesn't rely on OpenGL contexts or API specifics like
|
||||
framebuffers, and allows exposing the graphics device and command buffer from the adaptation. It's
|
||||
not necessarily suitable for easy integration of all types of content, in particular true 3D, so
|
||||
it'll likely get complemented by an alternative to QQuickFramebufferObject in future releases.
|
||||
|
||||
To perform runtime decisions based on the adaptation in use, use
|
||||
QSGRendererInterface from C++ and GraphicsInfo from QML. They can also be used
|
||||
to check the level of shader support (shading language, compilation approach).
|
||||
To perform runtime decisions based on the adaptation, use QSGRendererInterface from C++ and
|
||||
GraphicsInfo from QML. They can also be used to check the level of shader support: shading
|
||||
language, compilation approach, and so on.
|
||||
|
||||
When creating custom items, use the new QSGRectangleNode and QSGImageNode
|
||||
classes. These replace the now deprecated QSGSimpleRectNode and
|
||||
QSGSimpleTextureNode. Unlike their predecessors, the new classes are
|
||||
interfaces, and implementations are created via the factory functions
|
||||
QQuickWindow::createRectangleNode() and QQuickWindow::createImageNode().
|
||||
When creating custom items, use the new QSGRectangleNode and QSGImageNode classes. These replace
|
||||
the now deprecated QSGSimpleRectNode and QSGSimpleTextureNode. Unlike their predecessors, these new
|
||||
classes are interfaces, and implementations are created via the QQuickWindow::createRectangleNode()
|
||||
and QQuickWindow::createImageNode() factory functions.
|
||||
|
||||
\section2 Advanced Configuration
|
||||
|
||||
The D3D12 adaptation can keep multiple frames in flight, similarly to modern
|
||||
game engines. This is somewhat different from the traditional render - swap -
|
||||
wait for vsync model and allows better GPU utilization at the expense of higher
|
||||
resource usage. This means that the renderer will be a number of frames ahead
|
||||
of what is displayed on the screen.
|
||||
The D3D12 adaptation can keep multiple frames in flight, similar to modern game engines. This is
|
||||
somewhat different from the traditional "render - swap - wait for vsync" model and allows for
|
||||
better GPU utilization at the expense of higher resource use. This means that the renderer will
|
||||
be a number of frames ahead of what is displayed on the screen.
|
||||
|
||||
For a discussion of flip model swap chains and the typical configuration
|
||||
parameters, refer to
|
||||
\l{https://software.intel.com/en-us/articles/sample-application-for-direct3d-12-flip-model-swap-chains}{this
|
||||
article}.
|
||||
For a discussion of flip model swap chains and the typical configuration parameters, refer to
|
||||
\l{https://software.intel.com/en-us/articles/sample-application-for-direct3d-12-flip-model-swap-chains}
|
||||
{Sample Application for Direct3D 12 Flip Model Swap Chains}.
|
||||
|
||||
Vertical synchronization is always enabled, meaning Present() is invoked with
|
||||
an interval of 1.
|
||||
Vertical synchronization is always enabled, meaning Present() is invoked with an interval of 1.
|
||||
|
||||
The configuration can be changed by setting the following environment variables:
|
||||
|
||||
\list
|
||||
|
||||
\li \c{QT_D3D_BUFFER_COUNT} - The number of swap chain buffers in range 2 - 4.
|
||||
The default value is 3.
|
||||
|
||||
\li \c{QT_D3D_FRAME_COUNT} - The number of frames prepared without blocking in
|
||||
range 1 - 4. Note that Present will start blocking after queuing 3 frames
|
||||
(regardless of \c{QT_D3D_BUFFER_COUNT}), unless the waitable object is in use.
|
||||
Note that every additional frame increases GPU resource usage since geometry
|
||||
and constant buffer data will have to be duplicated, and involves more
|
||||
bookkeeping on the CPU side. The default value is 2.
|
||||
|
||||
\li \c{QT_D3D_WAITABLE_SWAP_CHAIN_MAX_LATENCY} - When set to a value between 1
|
||||
and 16, the frame latency is set to the specified value. This changes the limit
|
||||
for Present() and will trigger a wait for an available swap chain buffer when
|
||||
beginning each frame. Refer to the article above for a detailed discussion.
|
||||
This is considered experimental for now and the default value is 0 (disabled).
|
||||
|
||||
\li \c{QT_D3D_BLOCKING_PRESENT} - When set to a non-zero value, there will be
|
||||
CPU-side wait for the GPU to finish its work after each call to Present. This
|
||||
effectively kills all parallelism but makes the behavior resemble the
|
||||
traditional swap-blocks-for-vsync model, and can therefore be useful in some
|
||||
special cases. This is not the same as setting the frame count to 1 because
|
||||
that still avoids blocking after Present, and may block only when starting to
|
||||
prepare the next frame (or may not block at all depending on the time gap
|
||||
between the frames). By default blocking present is disabled.
|
||||
|
||||
\endlist
|
||||
\table
|
||||
\header
|
||||
\li Environment variable
|
||||
\li Description
|
||||
\row
|
||||
\li \c{QT_D3D_BUFFER_COUNT}
|
||||
\li The number of swap chain buffers in range 2 - 4. The default value is 3.
|
||||
\row
|
||||
\li \c{QT_D3D_FRAME_COUNT}
|
||||
\li The number of frames prepared without blocking in range 1 - 4. The default value is 2.
|
||||
Present() starts blocking after queuing 3 frames (regardless of
|
||||
\c{QT_D3D_BUFFER_COUNT}), unless the waitable object is in use. Every additional frame
|
||||
increases GPU resource usage since geometry and constant buffer data needs to be
|
||||
duplicated, and involves more bookkeeping on the CPU side.
|
||||
\row
|
||||
\li \c{QT_D3D_WAITABLE_SWAP_CHAIN_MAX_LATENCY}
|
||||
\li The frame latency in range 1 - 16. The default value is 0 (disabled).
|
||||
Changes the limit for Present() and triggers a wait for an available swap chain buffer
|
||||
when beginning each frame. For a detailed discussion, see the article linked above.
|
||||
\note Currently, this behavior is experimental.
|
||||
\row
|
||||
\li \c{QT_D3D_BLOCKING_PRESENT}
|
||||
\li The time the CPU should wait, a non-zero value, for the GPU to finish its work after
|
||||
each call to Present(). The default value is 0 (disabled). This behavior effectively
|
||||
kills all parallelism but makes the behavior resemble the traditional
|
||||
swap-blocks-for-vsync model, which can be useful in some special cases. However, this
|
||||
behavior is not the same as setting the frame count to 1 because that still avoids
|
||||
blocking after Present(), and may only block when starting to prepare the next frame
|
||||
(or may not block at all depending on the time gap between the frames).
|
||||
\endtable
|
||||
|
||||
*/
|
||||
|
||||
|
@ -404,68 +374,72 @@ between the frames). By default blocking present is disabled.
|
|||
\title Qt Quick OpenVG Adaptation
|
||||
\page qtquick-visualcanvas-adaptations-openvg.html
|
||||
|
||||
The OpenVG adaptation is an alternative renderer for \l {Qt Quick} 2 that will
|
||||
renderer the contents of the scene graph using OpenVG commands to provide
|
||||
hardware-acclerated 2D vector and raster graphics. Much like the Software
|
||||
adaptation, some features and optimizations are no longer available. Most
|
||||
Qt Quick 2 applications will run without modification though any attempts to
|
||||
use unsupported features will be ignored.
|
||||
The OpenVG adaptation is an alternative renderer for \l{Qt Quick} 2 that renders the contents of
|
||||
the scene graph using OpenVG commands to provide hardware accelerated 2D vector and raster
|
||||
graphics. Much like the \l{qtquick-visualcanvas-adaptations-software.html}{Software Adaptation},
|
||||
some features and optimizations are no longer available. Most Qt Quick 2 applications will run
|
||||
without modification though any attempts to use unsupported features will be ignored.
|
||||
|
||||
\section2 EGL Requirement
|
||||
Unlike the defualt OpenGL Renderer, there is no built in support for acquiring
|
||||
an OpenVG context. This means that the renderer has the responsbility of
|
||||
requesting and managing the the current context. To do this EGL has to be used
|
||||
directly in the OpenVG renderer. This means that the OpenVG renderer is only
|
||||
usable with platform plugins that support creating QWindows with support for
|
||||
QSurfaceFormat::OpenVG. From this window, the renderer can get an EGLSurface
|
||||
which can be used with an EGLContext to render OpenVG content.
|
||||
|
||||
Unlike the default OpenGL Renderer, there is no built-in support to acquire an OpenVG context.
|
||||
This means that the renderer is responsible for requesting and managing the the current context.
|
||||
To do this, you use EGL directly in the OpenVG renderer. Consequently, the OpenVG renderer can only
|
||||
be used with platform plugins that support creating QWindows with support for
|
||||
QSurfaceFormat::OpenVG. From this window, the renderer can get an EGLSurface which can then be used
|
||||
with an EGLContext to render OpenVG content.
|
||||
|
||||
\section2 Renderer
|
||||
The OpenVG Renderer works by using the OpenVG API to send commands and data to
|
||||
a Vector GPU which will render the scenegraph in an accelerated manner, offloading
|
||||
graphics rendering from the CPU. Many operations like the rendering of rectangles
|
||||
and fonts glyphs ideal for OpenVG because these can be represented as paths which
|
||||
are stroked and filled. Rendering scenegraph items that would typically involve
|
||||
textures are handled in the OpenVG renderer by using VGImage. In addition when
|
||||
rendering to offscreen surfaces (like when using Layers), the scene subtree is
|
||||
rendered to a VGImage which can be reused in the scene.
|
||||
|
||||
The OpenVG Renderer uses the OpenVG API to send commands and data to a Vector GPU that renders the
|
||||
scene graph in an accelerated manner, offloading graphics rendering from the CPU. Many operations
|
||||
like the rendering of rectangles and font glyphs are ideal for OpenVG because they can be
|
||||
represented as paths which are stroked and filled. Rendering scene graph items that would typically
|
||||
involve textures are handled in the OpenVG renderer using VGImage. Additionally, when you render
|
||||
to offscreen surfaces (like with Layers), the scene subtree is rendered to a VGImage which can be
|
||||
reused in the scene.
|
||||
|
||||
\section2 Render Loop
|
||||
The OpenVG Renderer mirrors the behavior of the Basic render loop and will execute
|
||||
all OpenVG commands in a single thread.
|
||||
|
||||
See the \l{qtquick-visualcanvas-scenegraph.html}{Scene Graph page} for more
|
||||
information on render loops
|
||||
The OpenVG Renderer mirrors the behavior of the Basic render loop and it runs all OpenVG commands
|
||||
in a single thread.
|
||||
|
||||
For more information on render loops, see
|
||||
\l{qtquick-visualcanvas-scenegraph.html}{Qt Quick Scene Graph}.
|
||||
|
||||
\section2 Shader Effects
|
||||
ShaderEffect components in QtQuick 2 can not be rendered by the OpenVG adaptation.
|
||||
While it is possible to user ShaderEffectSource and QML Item Layers (which are both
|
||||
offscreen surfaces), it is not actually possible to apply shader effects to them
|
||||
via the ShaderEffect item. This is because OpenVG lacks an API for applying per
|
||||
vertex and per fragment shader operations. It may be possible however to take
|
||||
advantage of Image Filter operations in the OpenVG API to get similar effects to
|
||||
what is provided by ShaderEffects in custom items. To integrate custom OpenVG
|
||||
rendering, use QSGRenderNode in combination with QSGRendererInterface.
|
||||
|
||||
ShaderEffect components in QtQuick 2 can't be rendered by the OpenVG adaptation. While it's
|
||||
possible to use ShaderEffectSource and QML Item Layers (which are both offscreen surfaces), it's
|
||||
not possible to apply shader effects to them via the ShaderEffect item. This is because OpenVG
|
||||
lacks an API for applying per vertex and per fragment shader operations. However, you may be able
|
||||
to take advantage of Image Filter operations in the OpenVG API to get effects that are similar to
|
||||
what ShaderEffects provides in custom items. To integrate custom OpenVG rendering, use
|
||||
QSGRenderNode in combination with QSGRendererInterface.
|
||||
|
||||
\section2 Qt Graphical Effects Module
|
||||
\l {Qt Graphical Effects} uses ShaderEffect items to render effects. If you use
|
||||
graphical effects from this module, then you should not hide the source
|
||||
item so that the original item can still be rendered.
|
||||
|
||||
\l {Qt Graphical Effects} uses ShaderEffect items to render effects. If you use graphical effects
|
||||
from this module, then you shouldn't hide the source item so that the original item can still be
|
||||
rendered.
|
||||
|
||||
\section2 Particle Effects
|
||||
It is not possible to render particle effects with the OpenVG adaptation. Whenever
|
||||
possible, remove particles completely from the scene. Otherwise they will still
|
||||
require some processing, even though they are not visible.
|
||||
|
||||
It's not possible to render particle effects with the OpenVG adaptation. Whenever possible, remove
|
||||
particles completely from the scene. Otherwise they'll still require some processing, even though
|
||||
they are not visible.
|
||||
|
||||
\section2 Rendering Text
|
||||
The text rendering with the OpenVG adaptation is based on rendering the glpyh
|
||||
paths, and does not use the distance fields technique used by the OpenGL backend.
|
||||
|
||||
Text rendering with the OpenVG adaptation is based on rendering the glyph paths, and doesn't use
|
||||
the distance fields technique, unlike with the OpenGL backend.
|
||||
|
||||
\section2 Perspective Transforms
|
||||
The OpenVG API does not allow paths to be transformed with non-affine transforms,
|
||||
while it is possible with Qt Quick. This means that rendering components using
|
||||
paths like Rectangles and Text, when applying perspective transforms the OpenVG
|
||||
backend will first render to a VGImage before applying transformations. This uses
|
||||
more memory at runtime and is a slower path so avoid doing this if necessary.
|
||||
|
||||
The OpenVG API doesn't allow paths to be transformed with non-affine transforms, but it's
|
||||
possible with Qt Quick. Consquently, when you render components using paths like Rectangles and
|
||||
Text while applying perspective transforms, the OpenVG backend first renders to a VGImage before
|
||||
applying transformations. This behavior uses more memory at runtime and takes more time; avoid it
|
||||
if possible.
|
||||
|
||||
*/
|
||||
|
|
|
@ -191,7 +191,7 @@ public:
|
|||
void resetFirstItemPosition(qreal pos = 0.0) override;
|
||||
void adjustFirstItem(qreal forwards, qreal backwards, int changeBeforeVisible) override;
|
||||
|
||||
void createHighlight() override;
|
||||
void createHighlight(bool onDestruction = false) override;
|
||||
void updateHighlight() override;
|
||||
void resetHighlightPosition() override;
|
||||
|
||||
|
@ -696,9 +696,8 @@ void QQuickGridViewPrivate::adjustFirstItem(qreal forwards, qreal backwards, int
|
|||
gridItem->setPosition(gridItem->colPos(), gridItem->rowPos() + ((moveCount / columns) * rowSize()));
|
||||
}
|
||||
|
||||
void QQuickGridViewPrivate::createHighlight()
|
||||
void QQuickGridViewPrivate::createHighlight(bool onDestruction)
|
||||
{
|
||||
Q_Q(QQuickGridView);
|
||||
bool changed = false;
|
||||
if (highlight) {
|
||||
if (trackedItem == highlight)
|
||||
|
@ -714,6 +713,10 @@ void QQuickGridViewPrivate::createHighlight()
|
|||
changed = true;
|
||||
}
|
||||
|
||||
if (onDestruction)
|
||||
return;
|
||||
|
||||
Q_Q(QQuickGridView);
|
||||
if (currentItem) {
|
||||
QQuickItem *item = createHighlightItem();
|
||||
if (item) {
|
||||
|
|
|
@ -162,7 +162,7 @@ QQuickItemView::QQuickItemView(QQuickFlickablePrivate &dd, QQuickItem *parent)
|
|||
QQuickItemView::~QQuickItemView()
|
||||
{
|
||||
Q_D(QQuickItemView);
|
||||
d->clear();
|
||||
d->clear(true);
|
||||
if (d->ownModel)
|
||||
delete d->model;
|
||||
delete d->header;
|
||||
|
@ -1662,7 +1662,7 @@ void QQuickItemViewPrivate::updateCurrent(int modelIndex)
|
|||
releaseItem(oldCurrentItem);
|
||||
}
|
||||
|
||||
void QQuickItemViewPrivate::clear()
|
||||
void QQuickItemViewPrivate::clear(bool onDestruction)
|
||||
{
|
||||
Q_Q(QQuickItemView);
|
||||
currentChanges.reset();
|
||||
|
@ -1683,7 +1683,7 @@ void QQuickItemViewPrivate::clear()
|
|||
currentItem = nullptr;
|
||||
if (oldCurrentItem)
|
||||
emit q->currentItemChanged();
|
||||
createHighlight();
|
||||
createHighlight(onDestruction);
|
||||
trackedItem = nullptr;
|
||||
|
||||
if (requestedIndex >= 0) {
|
||||
|
@ -2352,15 +2352,16 @@ void QQuickItemView::destroyingItem(QObject *object)
|
|||
bool QQuickItemViewPrivate::releaseItem(FxViewItem *item)
|
||||
{
|
||||
Q_Q(QQuickItemView);
|
||||
if (!item || !model)
|
||||
if (!item)
|
||||
return true;
|
||||
if (trackedItem == item)
|
||||
trackedItem = nullptr;
|
||||
item->trackGeometry(false);
|
||||
|
||||
QQmlInstanceModel::ReleaseFlags flags = model->release(item->item);
|
||||
if (item->item) {
|
||||
if (flags == 0) {
|
||||
QQmlInstanceModel::ReleaseFlags flags = {};
|
||||
if (model && item->item) {
|
||||
flags = model->release(item->item);
|
||||
if (!flags) {
|
||||
// item was not destroyed, and we no longer reference it.
|
||||
QQuickItemPrivate::get(item->item)->setCulled(true);
|
||||
unrequestedItems.insert(item->item, model->indexOf(item->item, q));
|
||||
|
|
|
@ -163,7 +163,7 @@ public:
|
|||
int mapFromModel(int modelIndex) const;
|
||||
|
||||
virtual void init();
|
||||
virtual void clear();
|
||||
virtual void clear(bool onDestruction=false);
|
||||
virtual void updateViewport();
|
||||
|
||||
void regenerate(bool orientationChanged=false);
|
||||
|
@ -327,7 +327,7 @@ protected:
|
|||
virtual bool hasStickyHeader() const { return false; }
|
||||
virtual bool hasStickyFooter() const { return false; }
|
||||
|
||||
virtual void createHighlight() = 0;
|
||||
virtual void createHighlight(bool onDestruction = false) = 0;
|
||||
virtual void updateHighlight() = 0;
|
||||
virtual void resetHighlightPosition() = 0;
|
||||
virtual bool movingFromHighlight() { return false; }
|
||||
|
|
|
@ -81,7 +81,7 @@ public:
|
|||
FxViewItem *snapItemAt(qreal pos);
|
||||
|
||||
void init() override;
|
||||
void clear() override;
|
||||
void clear(bool onDestruction) override;
|
||||
|
||||
bool addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer) override;
|
||||
bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo) override;
|
||||
|
@ -98,7 +98,7 @@ public:
|
|||
void adjustFirstItem(qreal forwards, qreal backwards, int) override;
|
||||
void updateSizeChangesBeforeVisiblePos(FxViewItem *item, ChangeResult *removeResult) override;
|
||||
|
||||
void createHighlight() override;
|
||||
void createHighlight(bool onDestruction = false) override;
|
||||
void updateHighlight() override;
|
||||
void resetHighlightPosition() override;
|
||||
bool movingFromHighlight() override;
|
||||
|
@ -575,7 +575,7 @@ void QQuickListViewPrivate::init()
|
|||
::memset(sectionCache, 0, sizeof(QQuickItem*) * sectionCacheSize);
|
||||
}
|
||||
|
||||
void QQuickListViewPrivate::clear()
|
||||
void QQuickListViewPrivate::clear(bool onDestruction)
|
||||
{
|
||||
for (int i = 0; i < sectionCacheSize; ++i) {
|
||||
delete sectionCache[i];
|
||||
|
@ -587,7 +587,7 @@ void QQuickListViewPrivate::clear()
|
|||
releaseSectionItem(nextSectionItem);
|
||||
nextSectionItem = nullptr;
|
||||
lastVisibleSection = QString();
|
||||
QQuickItemViewPrivate::clear();
|
||||
QQuickItemViewPrivate::clear(onDestruction);
|
||||
}
|
||||
|
||||
FxViewItem *QQuickListViewPrivate::newViewItem(int modelIndex, QQuickItem *item)
|
||||
|
@ -634,7 +634,7 @@ void QQuickListViewPrivate::initializeViewItem(FxViewItem *item)
|
|||
bool QQuickListViewPrivate::releaseItem(FxViewItem *item)
|
||||
{
|
||||
if (!item || !model)
|
||||
return true;
|
||||
return QQuickItemViewPrivate::releaseItem(item);
|
||||
|
||||
QPointer<QQuickItem> it = item->item;
|
||||
QQuickListViewAttached *att = static_cast<QQuickListViewAttached*>(item->attached);
|
||||
|
@ -876,9 +876,8 @@ void QQuickListViewPrivate::updateSizeChangesBeforeVisiblePos(FxViewItem *item,
|
|||
QQuickItemViewPrivate::updateSizeChangesBeforeVisiblePos(item, removeResult);
|
||||
}
|
||||
|
||||
void QQuickListViewPrivate::createHighlight()
|
||||
void QQuickListViewPrivate::createHighlight(bool onDestruction)
|
||||
{
|
||||
Q_Q(QQuickListView);
|
||||
bool changed = false;
|
||||
if (highlight) {
|
||||
if (trackedItem == highlight)
|
||||
|
@ -896,6 +895,10 @@ void QQuickListViewPrivate::createHighlight()
|
|||
changed = true;
|
||||
}
|
||||
|
||||
if (onDestruction)
|
||||
return;
|
||||
|
||||
Q_Q(QQuickListView);
|
||||
if (currentItem) {
|
||||
QQuickItem *item = createHighlightItem();
|
||||
if (item) {
|
||||
|
|
|
@ -221,7 +221,7 @@ QQuickOpenGLShaderEffectCommon::~QQuickOpenGLShaderEffectCommon()
|
|||
clearSignalMappers(shaderType);
|
||||
}
|
||||
|
||||
void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QObject *obj, Key::ShaderType shaderType)
|
||||
void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType)
|
||||
{
|
||||
for (int i = 0; i < uniformData[shaderType].size(); ++i) {
|
||||
if (signalMappers[shaderType].at(i) == 0)
|
||||
|
@ -229,11 +229,12 @@ void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QObject *obj, Key
|
|||
const UniformData &d = uniformData[shaderType].at(i);
|
||||
auto mapper = signalMappers[shaderType].at(i);
|
||||
void *a = mapper;
|
||||
QObjectPrivate::disconnect(obj, mapper->signalIndex(), &a);
|
||||
QObjectPrivate::disconnect(item, mapper->signalIndex(), &a);
|
||||
if (d.specialType == UniformData::Sampler || d.specialType == UniformData::SamplerExternal) {
|
||||
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
|
||||
if (source) {
|
||||
QQuickItemPrivate::get(source)->derefWindow();
|
||||
if (item->window())
|
||||
QQuickItemPrivate::get(source)->derefWindow();
|
||||
QObject::disconnect(source, SIGNAL(destroyed(QObject*)), host, SLOT(sourceDestroyed(QObject*)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ struct Q_QUICK_PRIVATE_EXPORT QQuickOpenGLShaderEffectCommon
|
|||
|
||||
~QQuickOpenGLShaderEffectCommon();
|
||||
|
||||
void disconnectPropertySignals(QObject *item, Key::ShaderType shaderType);
|
||||
void disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType);
|
||||
void connectPropertySignals(QQuickItem *item, const QMetaObject *itemMetaObject, Key::ShaderType shaderType);
|
||||
void updateParseLog(bool ignoreAttributes);
|
||||
void lookThroughShaderCode(QQuickItem *item, const QMetaObject *itemMetaObject, Key::ShaderType shaderType, const QByteArray &code);
|
||||
|
|
|
@ -505,7 +505,7 @@ void QQuickOpenGLShaderEffectNode::markDirtyTexture()
|
|||
Q_EMIT dirtyTexture();
|
||||
}
|
||||
|
||||
void QQuickOpenGLShaderEffectNode::textureProviderDestroyed(const QObject *object)
|
||||
void QQuickOpenGLShaderEffectNode::textureProviderDestroyed(QObject *object)
|
||||
{
|
||||
Q_ASSERT(material());
|
||||
static_cast<QQuickOpenGLShaderEffectMaterial *>(material())->invalidateTextureProvider(object);
|
||||
|
|
|
@ -159,7 +159,7 @@ Q_SIGNALS:
|
|||
|
||||
private Q_SLOTS:
|
||||
void markDirtyTexture();
|
||||
void textureProviderDestroyed(const QObject *object);
|
||||
void textureProviderDestroyed(QObject *object);
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -120,16 +120,17 @@ QQuickRepeaterPrivate::~QQuickRepeaterPrivate()
|
|||
|
||||
Also, note that Repeater is \l {Item}-based, and can only repeat \l {Item}-derived objects.
|
||||
For example, it cannot be used to repeat QtObjects:
|
||||
\code
|
||||
//bad code
|
||||
|
||||
\qml
|
||||
// bad code:
|
||||
Item {
|
||||
Can't repeat QtObject as it doesn't derive from Item.
|
||||
// Can't repeat QtObject as it doesn't derive from Item.
|
||||
Repeater {
|
||||
model: 10
|
||||
QtObject {}
|
||||
}
|
||||
}
|
||||
\endcode
|
||||
\endqml
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
|
|
@ -515,6 +515,20 @@ QQuickShaderEffect::QQuickShaderEffect(QQuickItem *parent)
|
|||
m_impl = new QQuickGenericShaderEffect(this, this);
|
||||
}
|
||||
|
||||
QQuickShaderEffect::~QQuickShaderEffect()
|
||||
{
|
||||
// Delete the implementations now, while they still have have
|
||||
// valid references back to us.
|
||||
#if QT_CONFIG(opengl)
|
||||
auto *glImpl = m_glImpl;
|
||||
m_glImpl = nullptr;
|
||||
delete glImpl;
|
||||
#endif
|
||||
auto *impl = m_impl;
|
||||
m_impl = nullptr;
|
||||
delete impl;
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlproperty string QtQuick::ShaderEffect::fragmentShader
|
||||
|
||||
|
|
|
@ -92,6 +92,7 @@ public:
|
|||
Q_ENUM(Status)
|
||||
|
||||
QQuickShaderEffect(QQuickItem *parent = nullptr);
|
||||
~QQuickShaderEffect() override;
|
||||
|
||||
QByteArray fragmentShader() const;
|
||||
void setFragmentShader(const QByteArray &code);
|
||||
|
|
|
@ -868,6 +868,9 @@ void QQuickTableViewPrivate::syncLoadedTableRectFromLoadedTable()
|
|||
|
||||
void QQuickTableViewPrivate::forceLayout()
|
||||
{
|
||||
if (loadedItems.isEmpty())
|
||||
return;
|
||||
|
||||
clearEdgeSizeCache();
|
||||
RebuildOptions rebuildOptions = RebuildOption::LayoutOnly;
|
||||
|
||||
|
|
|
@ -1403,7 +1403,7 @@ QVariant QQuickTextControl::inputMethodQuery(Qt::InputMethodQuery property, QVar
|
|||
case Qt::ImAnchorPosition:
|
||||
return QVariant(d->cursor.anchor() - block.position());
|
||||
case Qt::ImAbsolutePosition:
|
||||
return QVariant(d->cursor.anchor());
|
||||
return QVariant(d->cursor.position());
|
||||
case Qt::ImTextAfterCursor:
|
||||
{
|
||||
int maxLength = argument.isValid() ? argument.toInt() : 1024;
|
||||
|
|
|
@ -258,7 +258,7 @@ QSGGeometry *QSGBasicInternalImageNode::updateGeometry(const QRectF &targetRect,
|
|||
xs[1].tx = innerSourceRect.left();
|
||||
xs += 2;
|
||||
}
|
||||
if (innerTargetRect.width() != 0) {
|
||||
if (innerTargetRect.width() != 0 && hTiles > 0) {
|
||||
xs[0].x = innerTargetRect.left();
|
||||
xs[0].tx = innerSourceRect.x() + (subSourceRect.left() - floorLeft) * innerSourceRect.width();
|
||||
++xs;
|
||||
|
@ -299,7 +299,7 @@ QSGGeometry *QSGBasicInternalImageNode::updateGeometry(const QRectF &targetRect,
|
|||
ys[1].ty = innerSourceRect.top();
|
||||
ys += 2;
|
||||
}
|
||||
if (innerTargetRect.height() != 0) {
|
||||
if (innerTargetRect.height() != 0 && vTiles > 0) {
|
||||
ys[0].y = innerTargetRect.top();
|
||||
ys[0].ty = innerSourceRect.y() + (subSourceRect.top() - floorTop) * innerSourceRect.height();
|
||||
++ys;
|
||||
|
|
|
@ -770,12 +770,15 @@ QSGThreadedRenderLoop::QSGThreadedRenderLoop()
|
|||
|
||||
QSGThreadedRenderLoop::~QSGThreadedRenderLoop()
|
||||
{
|
||||
qDeleteAll(pendingRenderContexts);
|
||||
delete sg;
|
||||
}
|
||||
|
||||
QSGRenderContext *QSGThreadedRenderLoop::createRenderContext(QSGContext *sg) const
|
||||
{
|
||||
return sg->createRenderContext();
|
||||
auto context = sg->createRenderContext();
|
||||
pendingRenderContexts.insert(context);
|
||||
return context;
|
||||
}
|
||||
|
||||
void QSGThreadedRenderLoop::maybePostPolishRequest(Window *w)
|
||||
|
@ -935,7 +938,10 @@ void QSGThreadedRenderLoop::handleExposure(QQuickWindow *window)
|
|||
Window win;
|
||||
win.window = window;
|
||||
win.actualWindowFormat = window->format();
|
||||
win.thread = new QSGRenderThread(this, QQuickWindowPrivate::get(window)->context);
|
||||
auto renderContext = QQuickWindowPrivate::get(window)->context;
|
||||
// The thread assumes ownership, so we don't need to delete it later.
|
||||
pendingRenderContexts.remove(renderContext);
|
||||
win.thread = new QSGRenderThread(this, renderContext);
|
||||
win.updateDuringSync = false;
|
||||
win.forceRenderPass = true; // also covered by polishAndSync(inExpose=true), but doesn't hurt
|
||||
m_windows << win;
|
||||
|
|
|
@ -124,6 +124,9 @@ private:
|
|||
|
||||
|
||||
QSGContext *sg;
|
||||
// Set of contexts that have been created but are now owned by
|
||||
// a rendering thread yet, as the window has never been exposed.
|
||||
mutable QSet<QSGRenderContext*> pendingRenderContexts;
|
||||
QAnimationDriver *m_animation_driver;
|
||||
QList<Window> m_windows;
|
||||
|
||||
|
|
|
@ -1314,9 +1314,13 @@ void QQuickWidget::mouseDoubleClickEvent(QMouseEvent *e)
|
|||
void QQuickWidget::showEvent(QShowEvent *)
|
||||
{
|
||||
Q_D(QQuickWidget);
|
||||
bool shouldTriggerUpdate = true;
|
||||
|
||||
if (!d->useSoftwareRenderer) {
|
||||
d->createContext();
|
||||
|
||||
if (d->offscreenWindow->openglContext()) {
|
||||
shouldTriggerUpdate = false;
|
||||
d->render(true);
|
||||
// render() may have led to a QQuickWindow::update() call (for
|
||||
// example, having a scene with a QQuickFramebufferObject::Renderer
|
||||
|
@ -1329,11 +1333,12 @@ void QQuickWidget::showEvent(QShowEvent *)
|
|||
d->updatePending = false;
|
||||
update();
|
||||
}
|
||||
} else {
|
||||
triggerUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldTriggerUpdate)
|
||||
triggerUpdate();
|
||||
|
||||
// note offscreenWindow is "QQuickOffScreenWindow" instance
|
||||
d->offscreenWindow->setVisible(true);
|
||||
if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
|
||||
|
|
|
@ -322,7 +322,7 @@ void tst_QQmlPreview::zoom()
|
|||
|
||||
for (auto testZoomFactor : {2.0f, 1.5f, 0.5f}) {
|
||||
m_client->triggerZoom(testZoomFactor);
|
||||
verifyZoomFactor(m_process, baseZoomFactor * testZoomFactor);
|
||||
verifyZoomFactor(m_process, testZoomFactor);
|
||||
}
|
||||
|
||||
m_client->triggerZoom(-1.0f);
|
||||
|
|
|
@ -712,8 +712,6 @@ language/statements/generators/yield-identifier-non-strict.js sloppyFails
|
|||
language/statements/let/block-local-closure-set-before-initialization.js fails
|
||||
language/statements/let/function-local-closure-set-before-initialization.js fails
|
||||
language/statements/let/global-closure-set-before-initialization.js fails
|
||||
language/statements/throw/S12.13_A2_T6.js strictFails
|
||||
language/statements/try/S12.14_A18_T6.js strictFails
|
||||
language/statements/try/scope-catch-block-lex-open.js fails
|
||||
language/statements/variable/binding-resolution.js sloppyFails
|
||||
language/statements/with/unscopables-inc-dec.js sloppyFails
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="" sourcelanguage="en">
|
||||
<context>
|
||||
<name>loadTranslation</name>
|
||||
<message>
|
||||
<source>translate it</source>
|
||||
<translation>translated</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
|
@ -0,0 +1,5 @@
|
|||
import QtQml 2.0
|
||||
|
||||
QtObject {
|
||||
property string translation: qsTr('translate it')
|
||||
}
|
|
@ -50,6 +50,9 @@ private slots:
|
|||
void application();
|
||||
void applicationProperties();
|
||||
void removeObjectsWhenDestroyed();
|
||||
void loadTranslation_data();
|
||||
void loadTranslation();
|
||||
|
||||
private:
|
||||
QString buildDir;
|
||||
QString srcDir;
|
||||
|
@ -241,6 +244,30 @@ void tst_qqmlapplicationengine::removeObjectsWhenDestroyed()
|
|||
QCOMPARE(test->rootObjects().size(), 0);
|
||||
}
|
||||
|
||||
void tst_qqmlapplicationengine::loadTranslation_data()
|
||||
{
|
||||
QTest::addColumn<QUrl>("qmlUrl");
|
||||
QTest::addColumn<QString>("translation");
|
||||
|
||||
QTest::newRow("local file") << testFileUrl("loadTranslation.qml")
|
||||
<< QStringLiteral("translated");
|
||||
QTest::newRow("qrc") << QUrl(QLatin1String("qrc:///data/loadTranslation.qml"))
|
||||
<< QStringLiteral("translated");
|
||||
}
|
||||
|
||||
void tst_qqmlapplicationengine::loadTranslation()
|
||||
{
|
||||
QFETCH(QUrl, qmlUrl);
|
||||
QFETCH(QString, translation);
|
||||
|
||||
QQmlApplicationEngine test(qmlUrl);
|
||||
QVERIFY(!test.rootObjects().isEmpty());
|
||||
|
||||
QObject *rootObject = test.rootObjects().first();
|
||||
QVERIFY(rootObject);
|
||||
|
||||
QCOMPARE(rootObject->property("translation").toString(), translation);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qqmlapplicationengine)
|
||||
|
||||
|
|
|
@ -5,6 +5,9 @@ macx:CONFIG -= app_bundle
|
|||
|
||||
SOURCES += tst_qqmlapplicationengine.cpp
|
||||
TESTDATA += data/*
|
||||
RESOURCES += tst_qqmlapplicationengine.qrc
|
||||
|
||||
include (../../shared/util.pri)
|
||||
QT += core-private gui-private qml-private network testlib
|
||||
|
||||
TRANSLATIONS = data/i18n/qml_ja.ts
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>data/loadTranslation.qml</file>
|
||||
<file>data/i18n/qml.qm</file>
|
||||
</qresource>
|
||||
</RCC>
|
|
@ -0,0 +1,14 @@
|
|||
import QtQml 2.0
|
||||
import Test.Singletons 1.0
|
||||
|
||||
QtObject {
|
||||
property Component singletonAccessor : Component {
|
||||
QtObject {
|
||||
property var singletonHolder;
|
||||
property int result: singletonHolder.testVar
|
||||
}
|
||||
}
|
||||
|
||||
property int firstLookup: singletonAccessor.createObject(this, { singletonHolder: CppSingleton1 }).result;
|
||||
property int secondLookup: singletonAccessor.createObject(this, { singletonHolder: CppSingleton2 }).result;
|
||||
}
|
|
@ -369,6 +369,7 @@ private slots:
|
|||
void intMinDividedByMinusOne();
|
||||
void undefinedPropertiesInObjectWrapper();
|
||||
void hugeRegexpQuantifiers();
|
||||
void singletonTypeWrapperLookup();
|
||||
|
||||
private:
|
||||
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
|
||||
|
@ -9007,6 +9008,55 @@ void tst_qqmlecmascript::hugeRegexpQuantifiers()
|
|||
QVERIFY(value.isRegExp());
|
||||
}
|
||||
|
||||
struct CppSingleton1 : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int testVar MEMBER testVar CONSTANT)
|
||||
public:
|
||||
const int testVar = 0;
|
||||
};
|
||||
|
||||
struct CppSingleton2 : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int testVar MEMBER testVar CONSTANT)
|
||||
public:
|
||||
const int testVar = 1;
|
||||
};
|
||||
|
||||
void tst_qqmlecmascript::singletonTypeWrapperLookup()
|
||||
{
|
||||
QQmlEngine engine;
|
||||
|
||||
auto singletonTypeId1 = qmlRegisterSingletonType<CppSingleton1>("Test.Singletons", 1, 0, "CppSingleton1",
|
||||
[](QQmlEngine *, QJSEngine *) -> QObject * {
|
||||
return new CppSingleton1;
|
||||
});
|
||||
|
||||
auto singletonTypeId2 = qmlRegisterSingletonType<CppSingleton2>("Test.Singletons", 1, 0, "CppSingleton2",
|
||||
[](QQmlEngine *, QJSEngine *) -> QObject * {
|
||||
return new CppSingleton2;
|
||||
});
|
||||
|
||||
auto cleanup = qScopeGuard([&]() {
|
||||
QQmlMetaType::unregisterType(singletonTypeId1);
|
||||
QQmlMetaType::unregisterType(singletonTypeId2);
|
||||
});
|
||||
|
||||
QQmlComponent component(&engine, testFileUrl("SingletonLookupTest.qml"));
|
||||
QScopedPointer<QObject> test(component.create());
|
||||
QVERIFY2(!test.isNull(), qPrintable(component.errorString()));
|
||||
|
||||
auto singleton1 = engine.singletonInstance<CppSingleton1*>(singletonTypeId1);
|
||||
QVERIFY(singleton1);
|
||||
|
||||
auto singleton2 = engine.singletonInstance<CppSingleton2*>(singletonTypeId2);
|
||||
QVERIFY(singleton2);
|
||||
|
||||
QCOMPARE(test->property("firstLookup").toInt(), singleton1->testVar);
|
||||
QCOMPARE(test->property("secondLookup").toInt(), singleton2->testVar);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qqmlecmascript)
|
||||
|
||||
#include "tst_qqmlecmascript.moc"
|
||||
|
|
|
@ -54,6 +54,7 @@ private slots:
|
|||
void noSubstitutionTemplateLiteral();
|
||||
void templateLiteral();
|
||||
void leadingSemicolonInClass();
|
||||
void templatedReadonlyProperty();
|
||||
|
||||
private:
|
||||
QStringList excludedDirs;
|
||||
|
@ -289,6 +290,15 @@ void tst_qqmlparser::leadingSemicolonInClass()
|
|||
QVERIFY(parser.parseProgram());
|
||||
}
|
||||
|
||||
void tst_qqmlparser::templatedReadonlyProperty()
|
||||
{
|
||||
QQmlJS::Engine engine;
|
||||
QQmlJS::Lexer lexer(&engine);
|
||||
lexer.setCode(QLatin1String("A { readonly property list<B> listfoo: [ C{} ] }"), 1);
|
||||
QQmlJS::Parser parser(&engine);
|
||||
QVERIFY(parser.parse());
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qqmlparser)
|
||||
|
||||
#include "tst_qqmlparser.moc"
|
||||
|
|
|
@ -1491,11 +1491,11 @@ void tst_QQuickPathView::undefinedPath()
|
|||
|
||||
// QPainterPath warnings are only received if QT_NO_DEBUG is not defined
|
||||
if (QLibraryInfo::isDebugBuild()) {
|
||||
QString warning1("QPainterPath::moveTo: Adding point where x or y is NaN or Inf, ignoring call");
|
||||
QTest::ignoreMessage(QtWarningMsg,qPrintable(warning1));
|
||||
QRegularExpression warning1("^QPainterPath::moveTo:.*ignoring call$");
|
||||
QTest::ignoreMessage(QtWarningMsg, warning1);
|
||||
|
||||
QString warning2("QPainterPath::lineTo: Adding point where x or y is NaN or Inf, ignoring call");
|
||||
QTest::ignoreMessage(QtWarningMsg,qPrintable(warning2));
|
||||
QRegularExpression warning2("^QPainterPath::lineTo:.*ignoring call$");
|
||||
QTest::ignoreMessage(QtWarningMsg, warning2);
|
||||
}
|
||||
|
||||
QQmlComponent c(&engine, testFileUrl("undefinedpath.qml"));
|
||||
|
|
|
@ -564,7 +564,10 @@ bool tst_SceneGraph::isRunningOnOpenGL()
|
|||
bool retval = false;
|
||||
QQuickView dummy;
|
||||
dummy.show();
|
||||
QTest::qWaitForWindowExposed(&dummy);
|
||||
if (!QTest::qWaitForWindowExposed(&dummy)) {
|
||||
[](){ QFAIL("Could not show a QQuickView"); }();
|
||||
return false;
|
||||
}
|
||||
if (dummy.rendererInterface()->graphicsApi() == QSGRendererInterface::OpenGL)
|
||||
retval = true;
|
||||
dummy.hide();
|
||||
|
|
|
@ -449,9 +449,6 @@ void tst_qquickwidget::reparentToNewWindow()
|
|||
qqw->setParent(&window2);
|
||||
qqw->show();
|
||||
|
||||
if (QGuiApplication::platformName() == QLatin1String("offscreen"))
|
||||
QEXPECT_FAIL("", "afterRendering not emitted after reparenting on offscreen", Continue);
|
||||
|
||||
QTRY_VERIFY(afterRenderingSpy.size() > 0);
|
||||
|
||||
QImage img = qqw->grabFramebuffer();
|
||||
|
|
Loading…
Reference in New Issue