aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorFrederik Gladhorn <frederik.gladhorn@digia.com>2014-10-09 18:13:54 +0200
committerFrederik Gladhorn <frederik.gladhorn@digia.com>2014-10-09 18:14:56 +0200
commite1dfb78667bd7e8dc418e12a9669404adea7e2cb (patch)
tree16f40a9852281a63c1f98af21c680bddedaa5258 /src
parent28949c9699014b4f7abba396c28dea207b29821e (diff)
parent26bbd784d67d151eee531e5ff57977a5353549f5 (diff)
Merge remote-tracking branch 'origin/5.4' into dev
Conflicts: src/quick/items/context2d/qquickcanvasitem.cpp src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp src/quick/scenegraph/coreapi/qsgrenderer.cpp src/quick/scenegraph/qsgadaptationlayer.cpp src/quick/scenegraph/qsgrenderloop.cpp src/quick/scenegraph/qsgthreadedrenderloop.cpp src/quick/scenegraph/qsgwindowsrenderloop.cpp src/quick/scenegraph/util/qsgatlastexture.cpp src/quick/scenegraph/util/qsgtexture.cpp src/quick/util/qquickprofiler_p.h Change-Id: Ie274c3baf72a8a0711c87d67238d68e2b2887429
Diffstat (limited to 'src')
-rw-r--r--src/imports/statemachine/childrenprivate.h6
-rw-r--r--src/imports/testlib/TestCase.qml32
-rw-r--r--src/particles/qquickimageparticle.cpp3
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp19
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp2
-rw-r--r--src/qml/compiler/qv4compileddata.cpp2
-rw-r--r--src/qml/compiler/qv4compiler.cpp25
-rw-r--r--src/qml/compiler/qv4compiler_p.h9
-rw-r--r--src/qml/debugger/qqmlabstractprofileradapter.cpp10
-rw-r--r--src/qml/debugger/qqmlabstractprofileradapter_p.h13
-rw-r--r--src/qml/debugger/qqmlenginedebugservice.cpp8
-rw-r--r--src/qml/debugger/qqmlenginedebugservice_p.h2
-rw-r--r--src/qml/debugger/qqmlprofiler.cpp14
-rw-r--r--src/qml/debugger/qqmlprofiler_p.h41
-rw-r--r--src/qml/debugger/qqmlprofilerdefinitions_p.h16
-rw-r--r--src/qml/debugger/qqmlprofilerservice.cpp25
-rw-r--r--src/qml/debugger/qqmlprofilerservice_p.h4
-rw-r--r--src/qml/debugger/qv4profileradapter.cpp7
-rw-r--r--src/qml/doc/snippets/code/src_script_qjsengine.cpp6
-rw-r--r--src/qml/doc/src/cppintegration/definetypes.qdoc2
-rw-r--r--src/qml/doc/src/cppintegration/exposecppattributes.qdoc2
-rw-r--r--src/qml/doc/src/cppintegration/extending-tutorial.qdoc188
-rw-r--r--src/qml/doc/src/qmllanguageref/documents/scope.qdoc4
-rw-r--r--src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc19
-rw-r--r--src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc2
-rw-r--r--src/qml/jit/qv4isel_masm.cpp2
-rw-r--r--src/qml/jsapi/qjsengine.cpp27
-rw-r--r--src/qml/jsapi/qjsvalue.cpp69
-rw-r--r--src/qml/jsapi/qjsvalue_p.h7
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp56
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp27
-rw-r--r--src/qml/jsruntime/qv4engine.cpp6
-rw-r--r--src/qml/jsruntime/qv4managed_p.h1
-rw-r--r--src/qml/jsruntime/qv4profiling.cpp38
-rw-r--r--src/qml/jsruntime/qv4profiling_p.h18
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp6
-rw-r--r--src/qml/jsruntime/qv4script.cpp2
-rw-r--r--src/qml/jsruntime/qv4string.cpp2
-rw-r--r--src/qml/jsruntime/qv4variantobject.cpp2
-rw-r--r--src/qml/qml/ftw/qqmlthread.cpp26
-rw-r--r--src/qml/qml/ftw/qqmlthread_p.h2
-rw-r--r--src/qml/qml/qqmlapplicationengine.cpp12
-rw-r--r--src/qml/qml/qqmldirparser.cpp27
-rw-r--r--src/qml/qml/qqmldirparser_p.h3
-rw-r--r--src/qml/qml/qqmlengine.cpp64
-rw-r--r--src/qml/qml/qqmlextensionplugin.cpp2
-rw-r--r--src/qml/qml/qqmlmetatype.cpp12
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp2
-rw-r--r--src/qml/qml/qqmlproperty.cpp7
-rw-r--r--src/qml/qml/qqmltypeloader.cpp2
-rw-r--r--src/qml/qml/v8/qv8engine.cpp305
-rw-r--r--src/qml/qml/v8/qv8engine_p.h20
-rw-r--r--src/qml/types/qqmlbind.cpp2
-rw-r--r--src/qml/types/qqmllistmodel.cpp11
-rw-r--r--src/qml/types/qqmlobjectmodel.cpp1
-rw-r--r--src/qml/util/qqmllistaccessor.cpp7
-rw-r--r--src/quick/doc/images/qml-blending-layered.pngbin0 -> 7582 bytes
-rw-r--r--src/quick/doc/images/qml-blending-nonlayered.pngbin0 -> 7707 bytes
-rw-r--r--src/quick/doc/images/qml-shadereffect-layereffect.pngbin0 -> 22264 bytes
-rw-r--r--src/quick/doc/images/qml-shadereffect-nolayereffect.pngbin0 -> 26718 bytes
-rw-r--r--src/quick/doc/images/qml-shadereffect-opacitymask.pngbin0 -> 15661 bytes
-rw-r--r--src/quick/doc/qtquick.qdocconf6
-rw-r--r--src/quick/doc/snippets/qml/layerblending.qml111
-rw-r--r--src/quick/doc/snippets/qml/layerwitheffect.qml111
-rw-r--r--src/quick/doc/snippets/qml/opacitymask.qml114
-rw-r--r--src/quick/doc/src/concepts/input/focus.qdoc2
-rw-r--r--src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc8
-rw-r--r--src/quick/doc/src/concepts/positioning/righttoleft.qdoc8
-rw-r--r--src/quick/doc/src/dynamicview-tutorial.qdoc34
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp9
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp6
-rw-r--r--src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp7
-rw-r--r--src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h3
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture.cpp19
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture_p.h6
-rw-r--r--src/quick/items/qquickborderimage.cpp213
-rw-r--r--src/quick/items/qquickdrag.cpp13
-rw-r--r--src/quick/items/qquickframebufferobject.cpp1
-rw-r--r--src/quick/items/qquickgridview.cpp2
-rw-r--r--src/quick/items/qquickimagebase_p_p.h2
-rw-r--r--src/quick/items/qquickitem.cpp111
-rw-r--r--src/quick/items/qquicklistview.cpp2
-rw-r--r--src/quick/items/qquickscreen.cpp34
-rw-r--r--src/quick/items/qquickscreen_p.h10
-rw-r--r--src/quick/items/qquickshadereffect.cpp24
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp60
-rw-r--r--src/quick/items/qquicktextcontrol.cpp6
-rw-r--r--src/quick/items/qquicktextcontrol_p.h2
-rw-r--r--src/quick/items/qquicktextcontrol_p_p.h2
-rw-r--r--src/quick/items/qquicktextnodeengine.cpp73
-rw-r--r--src/quick/items/qquicktextnodeengine_p.h14
-rw-r--r--src/quick/items/qquickview.cpp10
-rw-r--r--src/quick/items/qquickwindow.cpp13
-rw-r--r--src/quick/items/qquickwindow.h3
-rw-r--r--src/quick/items/qquickwindowmodule.cpp11
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp83
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer.cpp21
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h9
-rw-r--r--src/quick/scenegraph/qsgcontext.cpp135
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.cpp24
-rw-r--r--src/quick/scenegraph/qsgdefaultlayer.cpp13
-rw-r--r--src/quick/scenegraph/qsgdefaultlayer_p.h3
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp43
-rw-r--r--src/quick/scenegraph/qsgrenderloop_p.h2
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp21
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop_p.h1
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp48
-rw-r--r--src/quick/scenegraph/shaders/styledtext.vert4
-rw-r--r--src/quick/scenegraph/shaders/styledtext_core.vert4
-rw-r--r--src/quick/scenegraph/shaders/textmask.vert2
-rw-r--r--src/quick/scenegraph/shaders/textmask_core.vert2
-rw-r--r--src/quick/scenegraph/util/qsgatlastexture.cpp11
-rw-r--r--src/quick/scenegraph/util/qsgtexture.cpp2
-rw-r--r--src/quick/util/qquickanimatorcontroller.cpp9
-rw-r--r--src/quick/util/qquickanimatorjob.cpp28
-rw-r--r--src/quick/util/qquickanimatorjob_p.h7
-rw-r--r--src/quick/util/qquickpixmapcache.cpp53
-rw-r--r--src/quick/util/qquickprofiler.cpp18
-rw-r--r--src/quick/util/qquickprofiler_p.h42
-rw-r--r--src/quickwidgets/qquickwidget.cpp81
-rw-r--r--src/quickwidgets/qquickwidget_p.h1
121 files changed, 1915 insertions, 1031 deletions
diff --git a/src/imports/statemachine/childrenprivate.h b/src/imports/statemachine/childrenprivate.h
index 5e2d60e299..d66454ca1c 100644
--- a/src/imports/statemachine/childrenprivate.h
+++ b/src/imports/statemachine/childrenprivate.h
@@ -51,9 +51,6 @@ public:
{
QAbstractState *state = qobject_cast<QAbstractState*>(item);
if (state) {
- if (qobject_cast<QStateMachine*>(item))
- qmlInfo(static_cast<T *>(prop->object)) << "StateMachines should not be nested.";
-
item->setParent(prop->object);
} else {
QAbstractTransition *trans = qobject_cast<QAbstractTransition*>(item);
@@ -68,9 +65,6 @@ public:
{
QAbstractState *state = qobject_cast<QAbstractState*>(item);
if (state) {
- if (qobject_cast<QStateMachine*>(item))
- qmlInfo(static_cast<T *>(prop->object)) << "StateMachines should not be nested.";
-
item->setParent(prop->object);
}
static_cast<ChildrenPrivate<T>*>(prop->data)->children.append(item);
diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml
index 8d9f6822f4..700c9112eb 100644
--- a/src/imports/testlib/TestCase.qml
+++ b/src/imports/testlib/TestCase.qml
@@ -633,17 +633,45 @@ Item {
\since 5.4
\qmlmethod QtObject TestCase::findChild(parent, objectName)
- Returns the first child of \a parent with \a objectName,
- or \c null if no such item exists. Children are searched recursively.
+ Returns the first child of \a parent with \a objectName, or \c null if
+ no such item exists. Both visual and non-visual children are searched
+ recursively, with visual children being searched first.
\code
compare(findChild(item, "childObject"), expectedChildObject);
\endcode
*/
function findChild(parent, objectName) {
+ // First, search the visual item hierarchy.
+ var child = qtest_findVisualChild(parent, objectName);
+ if (child)
+ return child;
+
+ // If it's not a visual child, it might be a QObject child.
return qtest_results.findChild(parent, objectName);
}
+ /*! \internal */
+ function qtest_findVisualChild(parent, objectName) {
+ if (!parent || parent.children === undefined)
+ return null;
+
+ for (var i = 0; i < parent.children.length; ++i) {
+ // Is this direct child of ours the child we're after?
+ var child = parent.children[i];
+ if (child.objectName === objectName)
+ return child;
+ }
+
+ for (i = 0; i < parent.children.length; ++i) {
+ // Try the direct child's children.
+ child = qtest_findVisualChild(parent.children[i], objectName);
+ if (child)
+ return child;
+ }
+ return null;
+ }
+
/*!
\qmlmethod TestCase::tryCompare(obj, property, expected, timeout = 5000, message = "")
diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp
index 08d3142701..60a67d55a6 100644
--- a/src/particles/qquickimageparticle.cpp
+++ b/src/particles/qquickimageparticle.cpp
@@ -1223,6 +1223,9 @@ void QQuickImageParticle::buildParticleNodes(QSGNode** passThrough)
void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node)
{
+ if (!QOpenGLContext::currentContext())
+ return;
+
if (QOpenGLContext::currentContext()->isOpenGLES() && m_count * 4 > 0xffff) {
printf("ImageParticle: Too many particles - maximum 16,000 per ImageParticle.\n");//ES 2 vertex count limit is ushort
return;
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 34db06ca4c..a96fafac9b 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -1523,7 +1523,7 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
objectsSize += signalTableSize;
}
- const int totalSize = unitSize + importSize + objectOffsetTableSize + objectsSize;
+ const int totalSize = unitSize + importSize + objectOffsetTableSize + objectsSize + output.jsGenerator.stringTable.sizeOfTableAndData();
char *data = (char*)malloc(totalSize);
memcpy(data, jsUnit, unitSize);
if (jsUnit != compilationUnit->data)
@@ -1539,6 +1539,8 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
qmlUnit->offsetToObjects = unitSize + importSize;
qmlUnit->nObjects = output.objects.count();
qmlUnit->indexOfRootObject = output.indexOfRootObject;
+ qmlUnit->offsetToStringTable = totalSize - output.jsGenerator.stringTable.sizeOfTableAndData();
+ qmlUnit->stringTableSize = output.jsGenerator.stringTable.stringCount();
// write imports
char *importPtr = data + qmlUnit->offsetToImports;
@@ -1630,6 +1632,8 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
}
}
+ output.jsGenerator.stringTable.serialize(qmlUnit);
+
return qmlUnit;
}
@@ -1805,13 +1809,14 @@ static QV4::IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, QV4::IR::Membe
}
if (type->isCompositeSingleton()) {
- QQmlTypeData *tdata = qmlEngine->typeLoader.getType(type->singletonInstanceInfo()->url);
+ QQmlRefPointer<QQmlTypeData> tdata = qmlEngine->typeLoader.getType(type->singletonInstanceInfo()->url);
Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
- initMetaObjectResolver(resolver, qmlEngine->propertyCacheForType(tdata->compiledData()->metaTypeId));
- tdata->release();
- resolver->flags |= AllPropertiesAreFinal;
- return resolver->resolveMember(qmlEngine, resolver, member);
+ // When a singleton tries to reference itself, it may not be complete yet.
+ if (tdata->isComplete()) {
+ initMetaObjectResolver(resolver, qmlEngine->propertyCacheForType(tdata->compiledData()->metaTypeId));
+ resolver->flags |= AllPropertiesAreFinal;
+ return resolver->resolveMember(qmlEngine, resolver, member);
+ }
} else if (type->isSingleton()) {
const QMetaObject *singletonMeta = type->singletonInstanceInfo()->instanceMetaObject;
if (singletonMeta) { // QJSValue-based singletons cannot be accelerated
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index 90f775f781..13367efc3d 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -571,7 +571,7 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob
QV4::CompiledData::Property::Type dtype;
int metaType;
} builtinTypes[] = {
- { QV4::CompiledData::Property::Var, qMetaTypeId<QJSValue>() },
+ { QV4::CompiledData::Property::Var, QMetaType::QVariant },
{ QV4::CompiledData::Property::Variant, QMetaType::QVariant },
{ QV4::CompiledData::Property::Int, QMetaType::Int },
{ QV4::CompiledData::Property::Bool, QMetaType::Bool },
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index a5530e167d..d242fb7b3a 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -181,7 +181,7 @@ void CompilationUnit::markObjects(QV4::ExecutionEngine *e)
Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)
{
- return irDocument->jsGenerator.generateUnit();
+ return irDocument->jsGenerator.generateUnit(QV4::Compiler::JSUnitGenerator::GenerateWithoutStringTable);
}
QString Binding::valueAsString(const Unit *unit) const
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index d6f0bc8335..22107c4bd1 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -66,8 +66,11 @@ void QV4::Compiler::StringTableGenerator::clear()
stringDataSize = 0;
}
-void QV4::Compiler::StringTableGenerator::serialize(uint *stringTable, char *dataStart, char *stringData)
+void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
{
+ char *dataStart = reinterpret_cast<char *>(unit);
+ uint *stringTable = reinterpret_cast<uint *>(dataStart + unit->offsetToStringTable);
+ char *stringData = dataStart + unit->offsetToStringTable + unit->stringTableSize * sizeof(uint);
for (int i = 0; i < strings.size(); ++i) {
stringTable[i] = stringData - dataStart;
const QString &qstr = strings.at(i);
@@ -190,7 +193,7 @@ int QV4::Compiler::JSUnitGenerator::registerJSClass(int count, IR::ExprList *arg
return jsClasses.size() - 1;
}
-QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit()
+QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorOption option)
{
registerString(irModule->fileName);
foreach (QV4::IR::Function *f, irModule->functions) {
@@ -214,7 +217,7 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit()
functionDataSize += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), qmlIdDepsCount, qmlPropertyDepsCount);
}
- const int totalSize = unitSize + functionDataSize + jsClassDataSize + stringTable.sizeOfTableAndData();
+ const int totalSize = unitSize + functionDataSize + jsClassDataSize + (option == GenerateWithStringTable ? stringTable.sizeOfTableAndData() : 0);
char *data = (char *)malloc(totalSize);
memset(data, 0, totalSize);
QV4::CompiledData::Unit *unit = (QV4::CompiledData::Unit*)data;
@@ -234,8 +237,13 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit()
unit->offsetToConstantTable = unit->offsetToRegexpTable + unit->regexpTableSize * CompiledData::RegExp::calculateSize();
unit->jsClassTableSize = jsClasses.count();
unit->offsetToJSClassTable = unit->offsetToConstantTable + unit->constantTableSize * sizeof(ReturnedValue);
- unit->stringTableSize = stringTable.stringCount();
- unit->offsetToStringTable = unitSize + functionDataSize + jsClassDataSize;
+ if (option == GenerateWithStringTable) {
+ unit->stringTableSize = stringTable.stringCount();
+ unit->offsetToStringTable = unitSize + functionDataSize + jsClassDataSize;
+ } else {
+ unit->stringTableSize = 0;
+ unit->offsetToStringTable = 0;
+ }
unit->indexOfRootFunction = -1;
unit->sourceFileIndex = getStringId(irModule->fileName);
unit->nImports = 0;
@@ -287,11 +295,8 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit()
}
// write strings and string table
- {
- uint *stringTablePtr = (uint *)(data + unit->offsetToStringTable);
- char *string = data + unit->offsetToStringTable + unit->stringTableSize * sizeof(uint);
- stringTable.serialize(stringTablePtr, data, string);
- }
+ if (option == GenerateWithStringTable)
+ stringTable.serialize(unit);
return unit;
}
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index 109998dc33..7b349caaf8 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -63,7 +63,7 @@ struct Q_QML_PRIVATE_EXPORT StringTableGenerator {
void clear();
- void serialize(uint *stringTable, char *dataStart, char *stringData);
+ void serialize(CompiledData::Unit *unit);
private:
QHash<QString, int> stringToId;
@@ -90,7 +90,12 @@ struct Q_QML_PRIVATE_EXPORT JSUnitGenerator {
int registerJSClass(int count, IR::ExprList *args);
- QV4::CompiledData::Unit *generateUnit();
+ enum GeneratorOption {
+ GenerateWithStringTable,
+ GenerateWithoutStringTable
+ };
+
+ QV4::CompiledData::Unit *generateUnit(GeneratorOption option = GenerateWithStringTable);
// Returns bytes written
int writeFunction(char *f, int index, IR::Function *irFunction);
diff --git a/src/qml/debugger/qqmlabstractprofileradapter.cpp b/src/qml/debugger/qqmlabstractprofileradapter.cpp
index 1267503226..165772335a 100644
--- a/src/qml/debugger/qqmlabstractprofileradapter.cpp
+++ b/src/qml/debugger/qqmlabstractprofileradapter.cpp
@@ -69,13 +69,13 @@ QT_BEGIN_NAMESPACE
* If the profiler's thread is waiting for an initial start signal we can emit the signal over a
* \c Qt::DirectConnection to avoid the delay of the event loop.
*/
-void QQmlAbstractProfilerAdapter::startProfiling()
+void QQmlAbstractProfilerAdapter::startProfiling(quint64 features)
{
if (waiting)
- emit profilingEnabledWhileWaiting();
+ emit profilingEnabledWhileWaiting(features);
else
- emit profilingEnabled();
- running = true;
+ emit profilingEnabled(features);
+ featuresEnabled = features;
}
/*!
@@ -90,7 +90,7 @@ void QQmlAbstractProfilerAdapter::stopProfiling() {
emit profilingDisabledWhileWaiting();
else
emit profilingDisabled();
- running = false;
+ featuresEnabled = 0;
}
/*!
diff --git a/src/qml/debugger/qqmlabstractprofileradapter_p.h b/src/qml/debugger/qqmlabstractprofileradapter_p.h
index f06d51e8f7..03f6645178 100644
--- a/src/qml/debugger/qqmlabstractprofileradapter_p.h
+++ b/src/qml/debugger/qqmlabstractprofileradapter_p.h
@@ -59,12 +59,12 @@ class Q_QML_PRIVATE_EXPORT QQmlAbstractProfilerAdapter : public QObject, public
public:
QQmlAbstractProfilerAdapter(QQmlProfilerService *service) :
- service(service), waiting(true), running(false) {}
+ service(service), waiting(true), featuresEnabled(0) {}
virtual ~QQmlAbstractProfilerAdapter() {}
virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages) = 0;
- void startProfiling();
+ void startProfiling(quint64 features);
void stopProfiling();
@@ -73,13 +73,14 @@ public:
void stopWaiting() { waiting = false; }
void startWaiting() { waiting = true; }
- bool isRunning() const { return running; }
+ bool isRunning() const { return featuresEnabled != 0; }
+ quint64 features() const { return featuresEnabled; }
void synchronize(const QElapsedTimer &t) { emit referenceTimeKnown(t); }
signals:
- void profilingEnabled();
- void profilingEnabledWhileWaiting();
+ void profilingEnabled(quint64 features);
+ void profilingEnabledWhileWaiting(quint64 features);
void profilingDisabled();
void profilingDisabledWhileWaiting();
@@ -92,7 +93,7 @@ protected:
private:
bool waiting;
- bool running;
+ quint64 featuresEnabled;
};
QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmlenginedebugservice.cpp b/src/qml/debugger/qqmlenginedebugservice.cpp
index 399cc3e07d..cb533a0459 100644
--- a/src/qml/debugger/qqmlenginedebugservice.cpp
+++ b/src/qml/debugger/qqmlenginedebugservice.cpp
@@ -169,9 +169,13 @@ QQmlEngineDebugService::propertyData(QObject *obj, int propIdx)
return rv;
}
-QVariant QQmlEngineDebugService::valueContents(const QVariant &value) const
+QVariant QQmlEngineDebugService::valueContents(QVariant value) const
{
- int userType = value.userType();
+ // We can't send JS objects across the wire, so transform them to variant
+ // maps for serialization.
+ if (value.userType() == qMetaTypeId<QJSValue>())
+ value = value.value<QJSValue>().toVariant();
+ const int userType = value.userType();
//QObject * is not streamable.
//Convert all such instances to a String value
diff --git a/src/qml/debugger/qqmlenginedebugservice_p.h b/src/qml/debugger/qqmlenginedebugservice_p.h
index 1bab51d17b..940ca7d99c 100644
--- a/src/qml/debugger/qqmlenginedebugservice_p.h
+++ b/src/qml/debugger/qqmlenginedebugservice_p.h
@@ -111,7 +111,7 @@ private:
void buildStatesList(bool cleanList, const QList<QPointer<QObject> > &instances);
QQmlObjectData objectData(QObject *);
QQmlObjectProperty propertyData(QObject *, int);
- QVariant valueContents(const QVariant &defaultValue) const;
+ QVariant valueContents(QVariant defaultValue) const;
bool setBinding(int objectId, const QString &propertyName, const QVariant &expression, bool isLiteralValue, QString filename = QString(), int line = -1, int column = 0);
bool resetBinding(int objectId, const QString &propertyName);
bool setMethodBody(int objectId, const QString &method, const QString &body);
diff --git a/src/qml/debugger/qqmlprofiler.cpp b/src/qml/debugger/qqmlprofiler.cpp
index 3a647e704d..b102201ff1 100644
--- a/src/qml/debugger/qqmlprofiler.cpp
+++ b/src/qml/debugger/qqmlprofiler.cpp
@@ -82,9 +82,9 @@ QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEngin
QQmlAbstractProfilerAdapter(service)
{
engine->enableProfiler();
- connect(this, SIGNAL(profilingEnabled()), engine->profiler, SLOT(startProfiling()));
- connect(this, SIGNAL(profilingEnabledWhileWaiting()),
- engine->profiler, SLOT(startProfiling()), Qt::DirectConnection);
+ connect(this, SIGNAL(profilingEnabled(quint64)), engine->profiler, SLOT(startProfiling(quint64)));
+ connect(this, SIGNAL(profilingEnabledWhileWaiting(quint64)),
+ engine->profiler, SLOT(startProfiling(quint64)), Qt::DirectConnection);
connect(this, SIGNAL(profilingDisabled()), engine->profiler, SLOT(stopProfiling()));
connect(this, SIGNAL(profilingDisabledWhileWaiting()),
engine->profiler, SLOT(stopProfiling()), Qt::DirectConnection);
@@ -111,21 +111,21 @@ void QQmlProfilerAdapter::receiveData(const QList<QQmlProfilerData> &new_data)
}
-QQmlProfiler::QQmlProfiler() : enabled(false)
+QQmlProfiler::QQmlProfiler() : featuresEnabled(0)
{
static int metatype = qRegisterMetaType<QList<QQmlProfilerData> >();
Q_UNUSED(metatype);
m_timer.start();
}
-void QQmlProfiler::startProfiling()
+void QQmlProfiler::startProfiling(quint64 features)
{
- enabled = true;
+ featuresEnabled = features;
}
void QQmlProfiler::stopProfiling()
{
- enabled = false;
+ featuresEnabled = false;
reportData();
m_data.clear();
}
diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h
index 02cdbf0a4e..13e6b8ddae 100644
--- a/src/qml/debugger/qqmlprofiler_p.h
+++ b/src/qml/debugger/qqmlprofiler_p.h
@@ -56,14 +56,14 @@
QT_BEGIN_NAMESPACE
-#define Q_QML_PROFILE_IF_ENABLED(profiler, Code)\
- if (profiler && profiler->enabled) {\
+#define Q_QML_PROFILE_IF_ENABLED(feature, profiler, Code)\
+ if (profiler && (profiler->featuresEnabled & (1 << feature))) {\
Code;\
} else\
(void)0
-#define Q_QML_PROFILE(profiler, Method)\
- Q_QML_PROFILE_IF_ENABLED(profiler, profiler->Method)
+#define Q_QML_PROFILE(feature, profiler, Method)\
+ Q_QML_PROFILE_IF_ENABLED(feature, profiler, profiler->Method)
// This struct is somewhat dangerous to use:
// The messageType is a bit field. You can pack multiple messages into
@@ -162,10 +162,10 @@ public:
QQmlProfiler();
- bool enabled;
+ quint64 featuresEnabled;
public slots:
- void startProfiling();
+ void startProfiling(quint64 features);
void stopProfiling();
void reportData();
void setTimer(const QElapsedTimer &timer) { m_timer = timer; }
@@ -204,12 +204,14 @@ struct QQmlBindingProfiler : public QQmlProfilerHelper {
QQmlBindingProfiler(QQmlProfiler *profiler, const QString &url, int line, int column) :
QQmlProfilerHelper(profiler)
{
- Q_QML_PROFILE(profiler, startBinding(url, line, column));
+ Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileBinding, profiler,
+ startBinding(url, line, column));
}
~QQmlBindingProfiler()
{
- Q_QML_PROFILE(profiler, endRange<Binding>());
+ Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileBinding, profiler,
+ endRange<Binding>());
}
};
@@ -217,12 +219,14 @@ struct QQmlHandlingSignalProfiler : public QQmlProfilerHelper {
QQmlHandlingSignalProfiler(QQmlProfiler *profiler, QQmlBoundSignalExpression *expression) :
QQmlProfilerHelper(profiler)
{
- Q_QML_PROFILE(profiler, startHandlingSignal(expression->sourceLocation()));
+ Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileHandlingSignal, profiler,
+ startHandlingSignal(expression->sourceLocation()));
}
~QQmlHandlingSignalProfiler()
{
- Q_QML_PROFILE(profiler, endRange<QQmlProfiler::HandlingSignal>());
+ Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileHandlingSignal, profiler,
+ endRange<QQmlProfiler::HandlingSignal>());
}
};
@@ -230,12 +234,12 @@ struct QQmlCompilingProfiler : public QQmlProfilerHelper {
QQmlCompilingProfiler(QQmlProfiler *profiler, const QString &name) :
QQmlProfilerHelper(profiler)
{
- Q_QML_PROFILE(profiler, startCompiling(name));
+ Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCompiling, profiler, startCompiling(name));
}
~QQmlCompilingProfiler()
{
- Q_QML_PROFILE(profiler, endRange<Compiling>());
+ Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCompiling, profiler, endRange<Compiling>());
}
};
@@ -278,20 +282,20 @@ private:
QFiniteStack<Data> ranges;
};
-#define Q_QML_OC_PROFILE(profilerMember, Code)\
- Q_QML_PROFILE_IF_ENABLED(profilerMember.profiler, Code)
+#define Q_QML_OC_PROFILE(member, Code)\
+ Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, member.profiler, Code)
class QQmlObjectCreationProfiler : public QQmlVmeProfiler::Data {
public:
QQmlObjectCreationProfiler(QQmlProfiler *profiler) : profiler(profiler)
{
- Q_QML_PROFILE(profiler, startCreating());
+ Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCreating, profiler, startCreating());
}
~QQmlObjectCreationProfiler()
{
- Q_QML_PROFILE(profiler, endRange<QQmlProfilerDefinitions::Creating>());
+ Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCreating, profiler, endRange<QQmlProfilerDefinitions::Creating>());
}
void update(const QString &typeName, const QUrl &url, int line, int column)
@@ -312,7 +316,7 @@ public:
QQmlObjectCompletionProfiler(QQmlVmeProfiler *parent) :
profiler(parent->profiler)
{
- Q_QML_PROFILE_IF_ENABLED(profiler, {
+ Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler, {
QQmlVmeProfiler::Data data = parent->pop();
profiler->startCreating(data.m_typeName, data.m_url, data.m_line, data.m_column);
});
@@ -320,7 +324,8 @@ public:
~QQmlObjectCompletionProfiler()
{
- Q_QML_PROFILE(profiler, endRange<QQmlProfilerDefinitions::Creating>());
+ Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCreating, profiler,
+ endRange<QQmlProfilerDefinitions::Creating>());
}
private:
QQmlProfiler *profiler;
diff --git a/src/qml/debugger/qqmlprofilerdefinitions_p.h b/src/qml/debugger/qqmlprofilerdefinitions_p.h
index 7abff8857e..713134f394 100644
--- a/src/qml/debugger/qqmlprofilerdefinitions_p.h
+++ b/src/qml/debugger/qqmlprofilerdefinitions_p.h
@@ -124,6 +124,22 @@ struct QQmlProfilerDefinitions {
};
typedef QV4::Profiling::MemoryType MemoryType;
+
+ enum ProfileFeature {
+ ProfileJavaScript = QV4::Profiling::FeatureFunctionCall,
+ ProfileMemory = QV4::Profiling::FeatureMemoryAllocation,
+ ProfilePixmapCache,
+ ProfileSceneGraph,
+ ProfileAnimations,
+ ProfilePainting,
+ ProfileCompiling,
+ ProfileCreating,
+ ProfileBinding,
+ ProfileHandlingSignal,
+ ProfileInputEvents,
+
+ MaximumProfileFeature
+ };
};
QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmlprofilerservice.cpp b/src/qml/debugger/qqmlprofilerservice.cpp
index 6157d2f191..5ec8178f32 100644
--- a/src/qml/debugger/qqmlprofilerservice.cpp
+++ b/src/qml/debugger/qqmlprofilerservice.cpp
@@ -171,12 +171,12 @@ void QQmlProfilerService::addGlobalProfiler(QQmlAbstractProfilerAdapter *profile
// Global profiler, not connected to a specific engine.
// Global profilers are started whenever any engine profiler is started and stopped when
// all engine profilers are stopped.
- foreach (QQmlAbstractProfilerAdapter *engineProfiler, m_engineProfilers) {
- if (engineProfiler->isRunning()) {
- profiler->startProfiling();
- break;
- }
- }
+ quint64 features = 0;
+ foreach (QQmlAbstractProfilerAdapter *engineProfiler, m_engineProfilers)
+ features |= engineProfiler->features();
+
+ if (features != 0)
+ profiler->startProfiling(features);
}
void QQmlProfilerService::removeGlobalProfiler(QQmlAbstractProfilerAdapter *profiler)
@@ -206,7 +206,7 @@ void QQmlProfilerService::removeProfilerFromStartTimes(const QQmlAbstractProfile
*
* If any engine profiler is started like that also start all global profilers.
*/
-void QQmlProfilerService::startProfiling(QQmlEngine *engine)
+void QQmlProfilerService::startProfiling(QQmlEngine *engine, quint64 features)
{
QMutexLocker lock(configMutex());
@@ -218,7 +218,7 @@ void QQmlProfilerService::startProfiling(QQmlEngine *engine)
if (engine != 0) {
foreach (QQmlAbstractProfilerAdapter *profiler, m_engineProfilers.values(engine)) {
if (!profiler->isRunning()) {
- profiler->startProfiling();
+ profiler->startProfiling(features);
startedAny = true;
}
}
@@ -230,7 +230,7 @@ void QQmlProfilerService::startProfiling(QQmlEngine *engine)
i != m_engineProfilers.end(); ++i) {
if (!i.value()->isRunning()) {
engines << i.key();
- i.value()->startProfiling();
+ i.value()->startProfiling(features);
startedAny = true;
}
}
@@ -241,7 +241,7 @@ void QQmlProfilerService::startProfiling(QQmlEngine *engine)
if (startedAny) {
foreach (QQmlAbstractProfilerAdapter *profiler, m_globalProfilers) {
if (!profiler->isRunning())
- profiler->startProfiling();
+ profiler->startProfiling(features);
}
}
@@ -359,14 +359,17 @@ void QQmlProfilerService::messageReceived(const QByteArray &message)
QQmlDebugStream stream(&rwData, QIODevice::ReadOnly);
int engineId = -1;
+ quint64 features = std::numeric_limits<quint64>::max();
bool enabled;
stream >> enabled;
if (!stream.atEnd())
stream >> engineId;
+ if (!stream.atEnd())
+ stream >> features;
// If engineId == -1 objectForId() and then the cast will return 0.
if (enabled)
- startProfiling(qobject_cast<QQmlEngine *>(objectForId(engineId)));
+ startProfiling(qobject_cast<QQmlEngine *>(objectForId(engineId)), features);
else
stopProfiling(qobject_cast<QQmlEngine *>(objectForId(engineId)));
diff --git a/src/qml/debugger/qqmlprofilerservice_p.h b/src/qml/debugger/qqmlprofilerservice_p.h
index 5405905861..c4c40adc4f 100644
--- a/src/qml/debugger/qqmlprofilerservice_p.h
+++ b/src/qml/debugger/qqmlprofilerservice_p.h
@@ -78,8 +78,8 @@ public:
void addGlobalProfiler(QQmlAbstractProfilerAdapter *profiler);
void removeGlobalProfiler(QQmlAbstractProfilerAdapter *profiler);
- void startProfiling(QQmlEngine *engine = 0);
- void stopProfiling(QQmlEngine *engine = 0);
+ void startProfiling(QQmlEngine *engine, quint64 features = std::numeric_limits<quint64>::max());
+ void stopProfiling(QQmlEngine *engine);
QQmlProfilerService();
~QQmlProfilerService();
diff --git a/src/qml/debugger/qv4profileradapter.cpp b/src/qml/debugger/qv4profileradapter.cpp
index 19a6ea3e74..a5492ce805 100644
--- a/src/qml/debugger/qv4profileradapter.cpp
+++ b/src/qml/debugger/qv4profileradapter.cpp
@@ -41,9 +41,10 @@ QV4ProfilerAdapter::QV4ProfilerAdapter(QQmlProfilerService *service, QV4::Execut
QQmlAbstractProfilerAdapter(service)
{
engine->enableProfiler();
- connect(this, SIGNAL(profilingEnabled()), engine->profiler, SLOT(startProfiling()));
- connect(this, SIGNAL(profilingEnabledWhileWaiting()), engine->profiler, SLOT(startProfiling()),
- Qt::DirectConnection);
+ connect(this, SIGNAL(profilingEnabled(quint64)),
+ engine->profiler, SLOT(startProfiling(quint64)));
+ connect(this, SIGNAL(profilingEnabledWhileWaiting(quint64)),
+ engine->profiler, SLOT(startProfiling(quint64)), Qt::DirectConnection);
connect(this, SIGNAL(profilingDisabled()), engine->profiler, SLOT(stopProfiling()));
connect(this, SIGNAL(profilingDisabledWhileWaiting()), engine->profiler, SLOT(stopProfiling()),
Qt::DirectConnection);
diff --git a/src/qml/doc/snippets/code/src_script_qjsengine.cpp b/src/qml/doc/snippets/code/src_script_qjsengine.cpp
index b836fabf3d..7428cedcaf 100644
--- a/src/qml/doc/snippets/code/src_script_qjsengine.cpp
+++ b/src/qml/doc/snippets/code/src_script_qjsengine.cpp
@@ -79,12 +79,12 @@ if (result.isError())
//! [5]
-QPushButton button;
-QJSValue scriptButton = myEngine.newQObject(&button);
+QPushButton *button = new QPushButton;
+QJSValue scriptButton = myEngine.newQObject(button);
myEngine.globalObject().setProperty("button", scriptButton);
myEngine.evaluate("button.checkable = true");
-qDebug() << scriptButton.property("checkable").toBoolean();
+qDebug() << scriptButton.property("checkable").toBool();
scriptButton.property("show").call(); // call the show() slot
//! [5]
diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc
index 6aed2f1339..03607df2e5 100644
--- a/src/qml/doc/src/cppintegration/definetypes.qdoc
+++ b/src/qml/doc/src/cppintegration/definetypes.qdoc
@@ -47,7 +47,7 @@ features such as \e{attached properties} and \e{default properties} in C++.
demonstrated in the \l{Writing QML Extensions with C++} tutorial.)
-\section1 Registering C++ types with the QML type system
+\section1 Registering C++ Types with the QML Type System
A QObject-derived class can be registered with the QML type system to enable the
type to be used as a data type from within QML code.
diff --git a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
index 8f6836558a..9527229204 100644
--- a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
+++ b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
@@ -359,7 +359,7 @@ implementation, whereas an object-type property can be freely created and
destroyed through QML code.
-\section1 Exposing Methods (including Qt Slots)
+\section1 Exposing Methods (Including Qt Slots)
Any method of a QObject-derived type is accessible from QML code if it is:
diff --git a/src/qml/doc/src/cppintegration/extending-tutorial.qdoc b/src/qml/doc/src/cppintegration/extending-tutorial.qdoc
index aab729656b..b593753d33 100644
--- a/src/qml/doc/src/cppintegration/extending-tutorial.qdoc
+++ b/src/qml/doc/src/cppintegration/extending-tutorial.qdoc
@@ -26,9 +26,9 @@
****************************************************************************/
/*!
-\page qml-extending-tutorial-index.html tutorial
+\example tutorials/extending-qml
\title Writing QML Extensions with C++
-\brief tutorial about extending QML with Qt C++
+\brief Tutorial about extending QML with Qt C++.
The \l {Qt QML} module provides a set of APIs for extending QML through
C++ extensions. You can write extensions to add your own QML types, extend existing
@@ -38,33 +38,22 @@ This tutorial shows how to write a QML extension using C++ that includes
core QML features, including properties, signals and bindings. It also shows how
extensions can be deployed through plugins.
-You can find the source code for this tutorial in \c Qt's
-examples/qml/tutorials/extending directory.
-
-Tutorial chapters:
-
-\list 1
-\li \l{tutorials/extending/chapter1-basics}{Creating a New Type}
-\li \l{tutorials/extending/chapter2-methods}{Connecting to C++ Methods and Signals}
-\li \l{tutorials/extending/chapter3-bindings}{Property Binding}
-\li \l{tutorials/extending/chapter4-customPropertyTypes}{Using Custom Property Types}
-\li \l{tutorials/extending/chapter5-listproperties}{Using List Property Types}
-\li \l{tutorials/extending/chapter6-plugins}{Writing an Extension Plugin}
-\li \l{qml-extending-tutorial7.html}{In Summary}
-\endlist
-
Many of the topics covered in this tutorial are documented in further detail in
\l {qtqml-cppintegration-topic.html}{Integrating QML and C++} and its documentation
sub-topics. In particular, you may be interested in the sub-topics
\l{qtqml-cppintegration-exposecppattributes.html}{Exposing Attributes of C++ Classes to QML}
and \l {qtqml-cppintegration-definetypes.html}{Defining QML Types from C++}.
-*/
+\section1 Running the Tutorial Examples
-/*!
-\title Chapter 1: Creating a New Type
+The code in this tutorial is available as an example project with subprojects
+associated with each tutorial chapter. In \l{Qt Creator Manual}{Qt Creator}, open
+the \uicontrol Welcome mode and select the tutorial from \uicontrol Examples. In
+\uicontrol Edit mode, expand the \e extending-qml project, right-click on the
+subproject (chapter) you want to run and select \uicontrol Run.
-\example tutorials/extending/chapter1-basics
+\section1 Chapter 1: Creating a New Type
+\c extending-qml/chapter1-basics
A common task when extending QML is to provide a new QML type that supports some
custom functionality beyond what is provided by the built-in \l {Qt Quick QML Types}{Qt Quick types}.
@@ -83,7 +72,7 @@ a version of 1.0.
We want this \c PieChart type to be usable from QML like this:
-\code
+\badcode
import Charts 1.0
PieChart {
@@ -104,7 +93,7 @@ this new class must:
Here is our \c PieChart class, defined in \c piechart.h:
-\snippet tutorials/extending/chapter1-basics/piechart.h 0
+\snippet tutorials/extending-qml/chapter1-basics/piechart.h 0
The class inherits from QQuickPaintedItem because we want to override
QQuickPaintedItem::paint() in perform drawing operations with the QPainter API.
@@ -120,15 +109,15 @@ simply sets and returns the \c m_name and \c m_color values as appropriate, and
implements \c paint() to draw a simple pie chart. It also turns off the
QGraphicsItem::ItemHasNoContents flag to enable painting:
-\snippet tutorials/extending/chapter1-basics/piechart.cpp 0
+\snippet tutorials/extending-qml/chapter1-basics/piechart.cpp 0
\dots 0
-\snippet tutorials/extending/chapter1-basics/piechart.cpp 1
+\snippet tutorials/extending-qml/chapter1-basics/piechart.cpp 1
Now that we have defined the \c PieChart type, we will use it from QML. The \c app.qml
file creates a \c PieChart item and display the pie chart's details
using a standard QML \l Text item:
-\snippet tutorials/extending/chapter1-basics/app.qml 0
+\snippet tutorials/extending-qml/chapter1-basics/app.qml 0
Notice that although the color is specified as a string in QML, it is automatically
converted to a QColor object for the PieChart \c color property. Automatic conversions are
@@ -142,46 +131,46 @@ you don't register the type, \c app.qml won't be able to create a \c PieChart.
Here is the application \c main.cpp:
-\snippet tutorials/extending/chapter1-basics/main.cpp 0
+\snippet tutorials/extending-qml/chapter1-basics/main.cpp 0
This call to qmlRegisterType() registers the \c PieChart type as a type called "PieChart",
in a type namespace called "Charts", with a version of 1.0.
Lastly, we write a \c .pro project file that includes the files and the \c declarative library:
-\quotefile tutorials/extending/chapter1-basics/chapter1-basics.pro
+\quotefile tutorials/extending-qml/chapter1-basics/chapter1-basics.pro
Now we can build and run the application:
\image extending-tutorial-chapter1.png
-Try it yourself with the code in Qt's \c examples/qml/tutorials/extending/chapter1-basics directory.
-*/
-
-
-/*!
-\title Chapter 2: Connecting to C++ Methods and Signals
+\note You may see a warning \e {Expression ... depends on non-NOTIFYable properties:
+ PieChart::name}. This happens because we add a binding to the writable \c name
+ property, but haven't yet defined a notify signal for it. The QML engine therefore
+ cannot update the binding if the \c name value changes. This is addressed in
+ the following chapters.
-\example tutorials/extending/chapter2-methods
+\section1 Chapter 2: Connecting to C++ Methods and Signals
+\c extending-qml/chapter2-methods
Suppose we want \c PieChart to have a "clearChart()" method that erases the
chart and then emits a "chartCleared" signal. Our \c app.qml would be able
to call \c clearChart() and receive \c chartCleared() signals like this:
-\snippet tutorials/extending/chapter2-methods/app.qml 0
+\snippet tutorials/extending-qml/chapter2-methods/app.qml 0
\image extending-tutorial-chapter2.png
To do this, we add a \c clearChart() method and a \c chartCleared() signal
to our C++ class:
-\snippet tutorials/extending/chapter2-methods/piechart.h 0
+\snippet tutorials/extending-qml/chapter2-methods/piechart.h 0
\dots
-\snippet tutorials/extending/chapter2-methods/piechart.h 1
+\snippet tutorials/extending-qml/chapter2-methods/piechart.h 1
\dots
-\snippet tutorials/extending/chapter2-methods/piechart.h 2
+\snippet tutorials/extending-qml/chapter2-methods/piechart.h 2
\dots
-\snippet tutorials/extending/chapter2-methods/piechart.h 3
+\snippet tutorials/extending-qml/chapter2-methods/piechart.h 3
The use of Q_INVOKABLE makes the \c clearChart() method available to the
Qt Meta-Object system, and in turn, to QML. Note that it could have
@@ -191,23 +180,17 @@ slots are also callable from QML. Both of these approaches are valid.
The \c clearChart() method simply changes the color to Qt::transparent,
repaints the chart, then emits the \c chartCleared() signal:
-\snippet tutorials/extending/chapter2-methods/piechart.cpp 0
+\snippet tutorials/extending-qml/chapter2-methods/piechart.cpp 0
Now when we run the application and click the window, the pie chart
disappears, and the application outputs:
-\code
- The chart has been cleared
+\badcode
+ qml: The chart has been cleared
\endcode
-Try out the example yourself with the updated code in Qt's \c examples/qml/tutorials/extending/chapter2-methods directory.
-
-*/
-
-/*!
-\title Chapter 3: Adding Property Bindings
-
-\example tutorials/extending/chapter3-bindings
+\section1 Chapter 3: Adding Property Bindings
+\c extending-qml/chapter3-bindings
Property binding is a powerful feature of QML that allows values of different
types to be synchronized automatically. It uses signals to notify and update
@@ -216,7 +199,7 @@ other types' values when property values are changed.
Let's enable property bindings for the \c color property. That means
if we have code like this:
-\snippet tutorials/extending/chapter3-bindings/app.qml 0
+\snippet tutorials/extending-qml/chapter3-bindings/app.qml 0
\image extending-tutorial-chapter3.png
@@ -231,17 +214,17 @@ It's easy to enable property binding for the \c color property.
We add a \l{Qt's Property System}{NOTIFY} feature to its Q_PROPERTY() declaration to indicate that a "colorChanged" signal
is emitted whenever the value changes.
-\snippet tutorials/extending/chapter3-bindings/piechart.h 0
+\snippet tutorials/extending-qml/chapter3-bindings/piechart.h 0
\dots
-\snippet tutorials/extending/chapter3-bindings/piechart.h 1
+\snippet tutorials/extending-qml/chapter3-bindings/piechart.h 1
\dots
-\snippet tutorials/extending/chapter3-bindings/piechart.h 2
+\snippet tutorials/extending-qml/chapter3-bindings/piechart.h 2
\dots
-\snippet tutorials/extending/chapter3-bindings/piechart.h 3
+\snippet tutorials/extending-qml/chapter3-bindings/piechart.h 3
Then, we emit this signal in \c setPieSlice():
-\snippet tutorials/extending/chapter3-bindings/piechart.cpp 0
+\snippet tutorials/extending-qml/chapter3-bindings/piechart.cpp 0
It's important for \c setColor() to check that the color value has actually changed
before emitting \c colorChanged(). This ensures the signal is not emitted unnecessarily and
@@ -254,12 +237,9 @@ automatically updated and cannot be used as flexibly in QML. Also, since
bindings are invoked so often and relied upon in QML usage, users of your
custom QML types may see unexpected behavior if bindings are not implemented.
-*/
-
-/*!
-\title Chapter 4: Using Custom Property Types
+\section1 Chapter 4: Using Custom Property Types
-\example tutorials/extending/chapter4-customPropertyTypes
+\c extending-qml/chapter4-customPropertyTypes
The \c PieChart type currently has a string-type property and a color-type property.
It could have many other types of properties. For example, it could have an
@@ -299,57 +279,49 @@ For example, let's replace the use of the \c property with a type called
"PieSlice" that has a \c color property. Instead of assigning a color,
we assign an \c PieSlice value which itself contains a \c color:
-\snippet tutorials/extending/chapter4-customPropertyTypes/app.qml 0
+\snippet tutorials/extending-qml/chapter4-customPropertyTypes/app.qml 0
Like \c PieChart, this new \c PieSlice type inherits from QQuickPaintedItem and declares
its properties with Q_PROPERTY():
-\snippet tutorials/extending/chapter4-customPropertyTypes/pieslice.h 0
+\snippet tutorials/extending-qml/chapter4-customPropertyTypes/pieslice.h 0
To use it in \c PieChart, we modify the \c color property declaration
and associated method signatures:
-\snippet tutorials/extending/chapter4-customPropertyTypes/piechart.h 0
+\snippet tutorials/extending-qml/chapter4-customPropertyTypes/piechart.h 0
\dots
-\snippet tutorials/extending/chapter4-customPropertyTypes/piechart.h 1
+\snippet tutorials/extending-qml/chapter4-customPropertyTypes/piechart.h 1
\dots
-\snippet tutorials/extending/chapter4-customPropertyTypes/piechart.h 2
+\snippet tutorials/extending-qml/chapter4-customPropertyTypes/piechart.h 2
\dots
-\snippet tutorials/extending/chapter4-customPropertyTypes/piechart.h 3
+\snippet tutorials/extending-qml/chapter4-customPropertyTypes/piechart.h 3
There is one thing to be aware of when implementing \c setPieSlice(). The \c PieSlice
is a visual item, so it must be set as a child of the \c PieChart using
QQuickItem::setParentItem() so that the \c PieChart knows to paint this child
item when its contents are drawn:
-\snippet tutorials/extending/chapter4-customPropertyTypes/piechart.cpp 0
-
+\snippet tutorials/extending-qml/chapter4-customPropertyTypes/piechart.cpp 0
Like the \c PieChart type, the \c PieSlice type has to be registered
using qmlRegisterType() to be used from QML. As with \c PieChart, we'll add the
type to the "Charts" type namespace, version 1.0:
-\snippet tutorials/extending/chapter4-customPropertyTypes/main.cpp 0
+\snippet tutorials/extending-qml/chapter4-customPropertyTypes/main.cpp 0
\dots
-\snippet tutorials/extending/chapter4-customPropertyTypes/main.cpp 1
+\snippet tutorials/extending-qml/chapter4-customPropertyTypes/main.cpp 1
\dots
-\snippet tutorials/extending/chapter4-customPropertyTypes/main.cpp 2
-
-Try it out with the code in Qt's \c examples/qml/tutorials/extending/chapter4-customPropertyTypes directory.
-
-*/
-
+\snippet tutorials/extending-qml/chapter4-customPropertyTypes/main.cpp 2
-/*!
-\title Chapter 5: Using List Property Types
-
-\example tutorials/extending/chapter5-listproperties
+\section1 Chapter 5: Using List Property Types
+\c extending-qml/chapter5-listproperties
Right now, a \c PieChart can only have one \c PieSlice. Ideally a chart would
have multiple slices, with different colors and sizes. To do this, we could
have a \c slices property that accepts a list of \c PieSlice items:
-\snippet tutorials/extending/chapter5-listproperties/app.qml 0
+\snippet tutorials/extending-qml/chapter5-listproperties/app.qml 0
\image extending-tutorial-chapter5.png
@@ -360,11 +332,11 @@ function with a \c slices() function that returns a list of slices, and add
an internal \c append_slice() function (discussed below). We also use a QList to
store the internal list of slices as \c m_slices:
-\snippet tutorials/extending/chapter5-listproperties/piechart.h 0
+\snippet tutorials/extending-qml/chapter5-listproperties/piechart.h 0
\dots
-\snippet tutorials/extending/chapter5-listproperties/piechart.h 1
+\snippet tutorials/extending-qml/chapter5-listproperties/piechart.h 1
\dots
-\snippet tutorials/extending/chapter5-listproperties/piechart.h 2
+\snippet tutorials/extending-qml/chapter5-listproperties/piechart.h 2
Although the \c slices property does not have an associated \c WRITE function,
it is still modifiable because of the way QQmlListProperty works.
@@ -373,7 +345,7 @@ return a QQmlListProperty value and indicate that the internal
\c PieChart::append_slice() function is to be called whenever a request is made from QML
to add items to the list:
-\snippet tutorials/extending/chapter5-listproperties/piechart.cpp 0
+\snippet tutorials/extending-qml/chapter5-listproperties/piechart.cpp 0
The \c append_slice() function simply sets the parent item as before,
and adds the new item to the \c m_slices list. As you can see, the append function for a
@@ -384,15 +356,9 @@ The \c PieSlice class has also been modified to include \c fromAngle and \c angl
properties and to draw the slice according to these values. This is a straightforward
modification if you have read the previous pages in this tutorial, so the code is not shown here.
-The complete code can be seen in the updated \c examples/qml/tutorials/extending/chapter5-listproperties directory.
-
-*/
-
+\section1 Chapter 6: Writing an Extension Plugin
-/*!
-\title Chapter 6: Writing an Extension Plugin
-
-\example tutorials/extending/chapter6-plugins
+\c extending-qml/chapter6-plugins
Currently the \c PieChart and \c PieSlice types are used by \c app.qml,
which is displayed using a QQuickView in a C++ application. An alternative
@@ -408,17 +374,17 @@ and registers our QML types in the inherited \l{QQmlExtensionPlugin::}{registerT
Here is the \c ChartsPlugin definition in \c chartsplugin.h:
-\snippet tutorials/extending/chapter6-plugins/import/chartsplugin.h 0
+\snippet tutorials/extending-qml/chapter6-plugins/import/chartsplugin.h 0
And its implementation in \c chartsplugin.cpp:
-\snippet tutorials/extending/chapter6-plugins/import/chartsplugin.cpp 0
+\snippet tutorials/extending-qml/chapter6-plugins/import/chartsplugin.cpp 0
Then, we write a \c .pro project file that defines the project as a plugin library
and specifies with DESTDIR that library files should be built into a \c {../Charts}
directory.
-\quotefile tutorials/extending/chapter6-plugins/import/import.pro
+\quotefile tutorials/extending-qml/chapter6-plugins/import/import.pro
In this example, the \c Charts directory is located at the same level as the application
that uses our new import module. This way, the QML engine will find our module
@@ -434,7 +400,7 @@ to the same location as the plugin binary.
The \c qmldir file declares the module name and the plugin that is made available
by the module:
-\quotefile tutorials/extending/chapter6-plugins/import/qmldir
+\quotefile tutorials/extending-qml/chapter6-plugins/import/qmldir
Now we have a QML module that can be imported to any application, provided that the
QML engine knows where to find it. The example contains an executable that loads
@@ -448,31 +414,29 @@ import path to the current directory so that it finds the \c qmldir file:
The module "Charts" will be loaded by the QML engine, and the types provided by that
module will be available for use in any QML document which imports it.
-*/
-
-/*!
-\page qml-extending-tutorial7.html
-\title Chapter 7: In Summary
+\section1 Chapter 7: Summary
In this tutorial, we've shown the basic steps for creating a QML extension:
\list
-\li Define new QML types by subclassing QObject and registering them with qmlRegisterType()
-\li Add callable methods using Q_INVOKABLE or Qt slots, and connect to Qt signals with an \c onSignal syntax
+\li Define new QML types by subclassing QObject and registering them with
+ qmlRegisterType()
+\li Add callable methods using \l Q_INVOKABLE or Qt slots, and connect to Qt signals
+ with an \c onSignal syntax
\li Add property bindings by defining \l{Qt's Property System}{NOTIFY} signals
\li Define custom property types if the built-in types are not sufficient
\li Define list property types using QQmlListProperty
-\li Create a plugin library by defining a Qt plugin and writing a \c qmldir file
+\li Create a plugin library by defining a Qt plugin and writing a
+ \l {Module Definition qmldir Files}{qmldir} file
\endlist
-
The \l{Integrating QML and C++} documentation shows
other useful features that can be added to QML extensions. For example, we
could use \l{Default Properties}{default properties} to allow
slices to be added without using the \c slices property:
-\code
+\badcode
PieChart {
PieSlice { ... }
PieSlice { ... }
@@ -482,13 +446,11 @@ slices to be added without using the \c slices property:
Or randomly add and remove slices from time to time using \l{Property Value Sources}{property value sources}:
-\code
+\badcode
PieChart {
PieSliceRandomizer on slices {}
}
\endcode
-
-See the \l{Integrating QML and C++} documentation for more information.
-
+\sa {Integrating QML and C++}
*/
diff --git a/src/qml/doc/src/qmllanguageref/documents/scope.qdoc b/src/qml/doc/src/qmllanguageref/documents/scope.qdoc
index af59afe1fb..67ae881908 100644
--- a/src/qml/doc/src/qmllanguageref/documents/scope.qdoc
+++ b/src/qml/doc/src/qmllanguageref/documents/scope.qdoc
@@ -163,14 +163,14 @@ Item {
property string title
Text {
- id: title
+ id: titletype
text: "<b>" + title + "</b>"
font.pixelSize: 22
anchors.top: parent.top
}
Text {
- text: title.text
+ text: titletype.text
font.pixelSize: 18
anchors.bottom: parent.bottom
}
diff --git a/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc b/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc
index a3ea25c005..def2216cbd 100644
--- a/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc
+++ b/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc
@@ -210,6 +210,25 @@ typeinfo mymodule.qmltypes
as code completion for the types defined in your plugins.
\row
+ \li Dependency Declaration
+ \li
+ \code
+depends <ModuleIdentifier> <InitialVersion>
+ \endcode
+ \li Declares that this module depends on another.
+
+ Example:
+ \code
+depends MyOtherModule 1.0
+ \endcode
+
+ This declaration is necessary only in cases when the dependency is
+ hidden: for example, when the C++ code for one module is used to
+ load QML (perhaps conditionally) which then depends on other
+ modules. In such cases, the \c depends declaration is necessary
+ to include the other modules in application packages.
+
+ \row
\li Comment
\li
\code
diff --git a/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc b/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc
index 16e36f6f6d..1a154e5d5a 100644
--- a/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc
@@ -646,7 +646,7 @@ property is only invoked when the property is reassigned to a different object v
This basic type is provided by the QML language. Some enumeration values
are provided by the QtQuick import.
- \section1 Using the enumeration type in QML
+ \section1 Using the enumeration Type in QML
The \c enumeration type is a representation of a C++ \c enum type. It is
not possible to refer to the \c enumeration type in QML itself; instead, the
diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp
index 753626c811..5cf00f6d60 100644
--- a/src/qml/jit/qv4isel_masm.cpp
+++ b/src/qml/jit/qv4isel_masm.cpp
@@ -86,7 +86,7 @@ public:
void vprintf(const char* format, va_list argList) WTF_ATTRIBUTE_PRINTF(2, 0)
{
- const int written = vsnprintf(buf.data(), buf.size(), format, argList);
+ const int written = qvsnprintf(buf.data(), buf.size(), format, argList);
if (written > 0)
dest->write(buf.constData(), written);
memset(buf.data(), 0, qMin(written, buf.size()));
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index 58251fac96..0d2b394cd6 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -420,17 +420,19 @@ bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr)
QV4::ScopedValue v(scope, vp->getValue(engine->m_v4Engine));
return engine->metaTypeFromJS(v, type, ptr);
} else if (vp->value.isEmpty()) {
- // have a string based value without engine. Do conversion manually
- if (type == QMetaType::Bool) {
- *reinterpret_cast<bool*>(ptr) = vp->string.length() != 0;
- return true;
- }
- if (type == QMetaType::QString) {
- *reinterpret_cast<QString*>(ptr) = vp->string;
- return true;
- }
- double d = QV4::RuntimeHelpers::stringToNumber(vp->string);
- switch (type) {
+ if (vp->unboundData.userType() == QMetaType::QString) {
+ QString string = vp->unboundData.toString();
+ // have a string based value without engine. Do conversion manually
+ if (type == QMetaType::Bool) {
+ *reinterpret_cast<bool*>(ptr) = string.length() != 0;
+ return true;
+ }
+ if (type == QMetaType::QString) {
+ *reinterpret_cast<QString*>(ptr) = string;
+ return true;
+ }
+ double d = QV4::RuntimeHelpers::stringToNumber(string);
+ switch (type) {
case QMetaType::Int:
*reinterpret_cast<int*>(ptr) = QV4::Primitive::toInt32(d);
return true;
@@ -466,6 +468,9 @@ bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr)
return true;
default:
return false;
+ }
+ } else {
+ return QMetaType::convert(&vp->unboundData.data_ptr(), vp->unboundData.userType(), ptr, type);
}
} else {
switch (type) {
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index 891f17762c..47a764e641 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -58,14 +58,14 @@ QV4::ReturnedValue QJSValuePrivate::getValue(QV4::ExecutionEngine *e)
}
if (value.isEmpty()) {
- value = QV4::Encode(engine->newString(string));
+ value = QV4::Encode(engine->v8Engine->fromVariant(unboundData));
PersistentValuePrivate **listRoot = &engine->memoryManager->m_persistentValues;
prev = listRoot;
next = *listRoot;
*prev = this;
if (next)
next->prev = &this->next;
- string = QString();
+ unboundData.clear();
}
return value.asReturnedValue();
}
@@ -353,8 +353,21 @@ bool QJSValue::isVariant() const
*/
QString QJSValue::toString() const
{
- if (d->value.isEmpty())
- return d->string;
+ if (d->value.isEmpty()) {
+ if (d->unboundData.type() == QVariant::Map)
+ return QStringLiteral("[object Object]");
+ else if (d->unboundData.type() == QVariant::List) {
+ const QVariantList list = d->unboundData.toList();
+ QString result;
+ for (int i = 0; i < list.count(); ++i) {
+ if (i > 0)
+ result.append(QLatin1Char(','));
+ result.append(list.at(i).toString());
+ }
+ return result;
+ }
+ return d->unboundData.toString();
+ }
return d->value.toQStringNoThrow();
}
@@ -372,8 +385,14 @@ QString QJSValue::toString() const
*/
double QJSValue::toNumber() const
{
- if (d->value.isEmpty())
- return RuntimeHelpers::stringToNumber(d->string);
+ if (d->value.isEmpty()) {
+ if (d->unboundData.type() == QVariant::String)
+ return RuntimeHelpers::stringToNumber(d->unboundData.toString());
+ else if (d->unboundData.canConvert<double>())
+ return d->unboundData.value<double>();
+ else
+ return std::numeric_limits<double>::quiet_NaN();
+ }
QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0;
double dbl = d->value.toNumber();
@@ -398,8 +417,12 @@ double QJSValue::toNumber() const
*/
bool QJSValue::toBool() const
{
- if (d->value.isEmpty())
- return d->string.length() > 0;
+ if (d->value.isEmpty()) {
+ if (d->unboundData.userType() == QMetaType::QString)
+ return d->unboundData.toString().length() > 0;
+ else
+ return d->unboundData.toBool();
+ }
QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0;
bool b = d->value.toBoolean();
@@ -424,8 +447,12 @@ bool QJSValue::toBool() const
*/
qint32 QJSValue::toInt() const
{
- if (d->value.isEmpty())
- return QV4::Primitive::toInt32(RuntimeHelpers::stringToNumber(d->string));
+ if (d->value.isEmpty()) {
+ if (d->unboundData.userType() == QMetaType::QString)
+ return QV4::Primitive::toInt32(RuntimeHelpers::stringToNumber(d->unboundData.toString()));
+ else
+ return d->unboundData.toInt();
+ }
QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0;
qint32 i = d->value.toInt32();
@@ -450,8 +477,12 @@ qint32 QJSValue::toInt() const
*/
quint32 QJSValue::toUInt() const
{
- if (d->value.isEmpty())
- return QV4::Primitive::toUInt32(RuntimeHelpers::stringToNumber(d->string));
+ if (d->value.isEmpty()) {
+ if (d->unboundData.userType() == QMetaType::QString)
+ return QV4::Primitive::toUInt32(RuntimeHelpers::stringToNumber(d->unboundData.toString()));
+ else
+ return d->unboundData.toUInt();
+ }
QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0;
quint32 u = d->value.toUInt32();
@@ -487,7 +518,7 @@ quint32 QJSValue::toUInt() const
QVariant QJSValue::toVariant() const
{
if (d->value.isEmpty())
- return QVariant(d->string);
+ return d->unboundData;
return QV4::VariantObject::toVariant(d->value);
}
@@ -775,8 +806,10 @@ bool QJSValue::equals(const QJSValue& other) const
{
if (d->value.isEmpty()) {
if (other.d->value.isEmpty())
- return d->string == other.d->string;
- return js_equal(d->string, QV4::ValueRef(other.d->value));
+ return d->unboundData == other.d->unboundData;
+ if (d->unboundData.type() == QVariant::Map || d->unboundData.type() == QVariant::List)
+ return false;
+ return js_equal(d->unboundData.toString(), QV4::ValueRef(other.d->value));
}
if (other.d->value.isEmpty())
return other.equals(*this);
@@ -810,9 +843,11 @@ bool QJSValue::strictlyEquals(const QJSValue& other) const
{
if (d->value.isEmpty()) {
if (other.d->value.isEmpty())
- return d->string == other.d->string;
+ return d->unboundData == other.d->unboundData;
+ if (d->unboundData.type() == QVariant::Map || d->unboundData.type() == QVariant::List)
+ return false;
if (other.d->value.isString())
- return d->string == other.d->value.stringValue()->toQString();
+ return d->unboundData.toString() == other.d->value.stringValue()->toQString();
return false;
}
if (other.d->value.isEmpty())
diff --git a/src/qml/jsapi/qjsvalue_p.h b/src/qml/jsapi/qjsvalue_p.h
index e66c1bcde4..43a3a74e38 100644
--- a/src/qml/jsapi/qjsvalue_p.h
+++ b/src/qml/jsapi/qjsvalue_p.h
@@ -51,6 +51,7 @@
#include <private/qv4string_p.h>
#include <private/qv4engine_p.h>
#include <private/qv4object_p.h>
+#include <private/qflagpointer_p.h>
QT_BEGIN_NAMESPACE
@@ -72,8 +73,8 @@ public:
Q_ASSERT(!value.isEmpty());
}
QJSValuePrivate(const QString &s)
- : PersistentValuePrivate(QV4::Primitive::emptyValue().asReturnedValue())
- , string(s)
+ : PersistentValuePrivate(QV4::Primitive::emptyValue().asReturnedValue()),
+ unboundData(s)
{
}
@@ -81,7 +82,7 @@ public:
static QJSValuePrivate *get(const QJSValue &v) { return v.d; }
- QString string;
+ QVariant unboundData;
};
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index f7940c9602..d58dbb91d4 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -678,6 +678,60 @@ bool ArrayElementLessThan::operator()(Value v1, Value v2) const
return p1s->toQString() < p2s->toQString();
}
+template <typename RandomAccessIterator, typename T, typename LessThan>
+void sortHelper(RandomAccessIterator start, RandomAccessIterator end, const T &t, LessThan lessThan)
+{
+top:
+ int span = int(end - start);
+ if (span < 2)
+ return;
+
+ --end;
+ RandomAccessIterator low = start, high = end - 1;
+ RandomAccessIterator pivot = start + span / 2;
+
+ if (lessThan(*end, *start))
+ qSwap(*end, *start);
+ if (span == 2)
+ return;
+
+ if (lessThan(*pivot, *start))
+ qSwap(*pivot, *start);
+ if (lessThan(*end, *pivot))
+ qSwap(*end, *pivot);
+ if (span == 3)
+ return;
+
+ qSwap(*pivot, *end);
+
+ while (low < high) {
+ while (low < high && lessThan(*low, *end))
+ ++low;
+
+ while (high > low && lessThan(*end, *high))
+ --high;
+
+ if (low < high) {
+ qSwap(*low, *high);
+ ++low;
+ --high;
+ } else {
+ break;
+ }
+ }
+
+ if (lessThan(*low, *end))
+ ++low;
+
+ qSwap(*end, *low);
+ sortHelper(start, low, t, lessThan);
+
+ start = low + 1;
+ ++end;
+ goto top;
+}
+
+
void ArrayData::sort(ExecutionContext *context, Object *thisObject, const ValueRef comparefn, uint len)
{
if (!len)
@@ -769,7 +823,7 @@ void ArrayData::sort(ExecutionContext *context, Object *thisObject, const ValueR
ArrayElementLessThan lessThan(context, thisObject, comparefn);
Value *begin = thisObject->arrayData()->arrayData();
- std::sort(begin, begin + len, lessThan);
+ sortHelper(begin, begin + len, *begin, lessThan);
#ifdef CHECK_SPARSE_ARRAYS
thisObject->initSparseArray();
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index 67d247de28..66601b64e5 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -550,16 +550,7 @@ static inline QDateTime ToDateTime(double t, Qt::TimeSpec spec)
{
if (std::isnan(t))
return QDateTime();
- if (spec == Qt::LocalTime)
- t = LocalTime(t);
- int year = int(YearFromTime(t));
- int month = int(MonthFromTime(t) + 1);
- int day = int(DateFromTime(t));
- int hours = HourFromTime(t);
- int mins = MinFromTime(t);
- int secs = SecFromTime(t);
- int ms = msFromTime(t);
- return QDateTime(QDate(year, month, day), QTime(hours, mins, secs, ms), spec);
+ return QDateTime::fromMSecsSinceEpoch(t, spec);
}
static inline QString ToString(double t)
@@ -586,7 +577,7 @@ static inline QString ToUTCString(double t)
{
if (std::isnan(t))
return QStringLiteral("Invalid Date");
- return ToDateTime(t, Qt::UTC).toString() + QStringLiteral(" GMT");
+ return ToDateTime(t, Qt::UTC).toString();
}
static inline QString ToDateString(double t)
@@ -1029,7 +1020,7 @@ ReturnedValue DatePrototype::method_setUTCMilliseconds(CallContext *ctx)
double t = self->date().asDouble();
double ms = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
- self->date().setDouble(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))));
+ self->date().setDouble(TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))));
return self->date().asReturnedValue();
}
@@ -1056,7 +1047,7 @@ ReturnedValue DatePrototype::method_setUTCSeconds(CallContext *ctx)
double t = self->date().asDouble();
double sec = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
double ms = (ctx->d()->callData->argc < 2) ? msFromTime(t) : ctx->d()->callData->args[1].toNumber();
- t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms))));
+ t = TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms)));
self->date().setDouble(t);
return self->date().asReturnedValue();
}
@@ -1086,7 +1077,7 @@ ReturnedValue DatePrototype::method_setUTCMinutes(CallContext *ctx)
double min = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
double sec = (ctx->d()->callData->argc < 2) ? SecFromTime(t) : ctx->d()->callData->args[1].toNumber();
double ms = (ctx->d()->callData->argc < 3) ? msFromTime(t) : ctx->d()->callData->args[2].toNumber();
- t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms))));
+ t = TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms)));
self->date().setDouble(t);
return self->date().asReturnedValue();
}
@@ -1118,7 +1109,7 @@ ReturnedValue DatePrototype::method_setUTCHours(CallContext *ctx)
double min = (ctx->d()->callData->argc < 2) ? MinFromTime(t) : ctx->d()->callData->args[1].toNumber();
double sec = (ctx->d()->callData->argc < 3) ? SecFromTime(t) : ctx->d()->callData->args[2].toNumber();
double ms = (ctx->d()->callData->argc < 4) ? msFromTime(t) : ctx->d()->callData->args[3].toNumber();
- t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms))));
+ t = TimeClip(MakeDate(Day(t), MakeTime(hour, min, sec, ms)));
self->date().setDouble(t);
return self->date().asReturnedValue();
}
@@ -1144,7 +1135,7 @@ ReturnedValue DatePrototype::method_setUTCDate(CallContext *ctx)
double t = self->date().asDouble();
double date = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
- t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t))));
+ t = TimeClip(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)));
self->date().setDouble(t);
return self->date().asReturnedValue();
}
@@ -1172,7 +1163,7 @@ ReturnedValue DatePrototype::method_setUTCMonth(CallContext *ctx)
double t = self->date().asDouble();
double month = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
double date = (ctx->d()->callData->argc < 2) ? DateFromTime(t) : ctx->d()->callData->args[1].toNumber();
- t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t))));
+ t = TimeClip(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t)));
self->date().setDouble(t);
return self->date().asReturnedValue();
}
@@ -1213,7 +1204,7 @@ ReturnedValue DatePrototype::method_setUTCFullYear(CallContext *ctx)
double year = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
double month = (ctx->d()->callData->argc < 2) ? MonthFromTime(t) : ctx->d()->callData->args[1].toNumber();
double date = (ctx->d()->callData->argc < 3) ? DateFromTime(t) : ctx->d()->callData->args[2].toNumber();
- t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t))));
+ t = TimeClip(MakeDate(MakeDay(year, month, date), TimeWithinDay(t)));
self->date().setDouble(t);
return self->date().asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 88cd043d1e..ea075f9cbd 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -90,6 +90,8 @@ static ReturnedValue throwTypeError(CallContext *ctx)
return ctx->throwTypeError();
}
+const int MinimumStackSize = 256; // in kbytes
+
quintptr getStackLimit()
{
quintptr stackLimit;
@@ -149,7 +151,7 @@ quintptr getStackLimit()
#endif
// 256k slack
- return stackLimit + 256*1024;
+ return stackLimit + MinimumStackSize*1024;
}
@@ -203,6 +205,8 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
// set up stack limits
jsStackLimit = jsStackBase + JSStackLimit/sizeof(Value);
cStackLimit = getStackLimit();
+ if (!recheckCStackLimits())
+ qFatal("Fatal: Not enough stack space available for QML. Please increase the process stack size to more than %d KBytes.", MinimumStackSize);
Scope scope(this);
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index 36cf8f9424..ce0ee973e8 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -212,6 +212,7 @@ struct Q_QML_PRIVATE_EXPORT Managed
void *operator new(size_t, Managed *m) { return m; }
void *operator new(size_t, Managed::Data *m) { return m; }
+ void operator delete(void *, Managed::Data *) {}
};
Data data;
V4_MANAGED(Managed)
diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp
index 693af854da..f1bd1d55d9 100644
--- a/src/qml/jsruntime/qv4profiling.cpp
+++ b/src/qml/jsruntime/qv4profiling.cpp
@@ -53,7 +53,7 @@ FunctionCallProperties FunctionCall::resolve() const
}
-Profiler::Profiler(QV4::ExecutionEngine *engine) : enabled(false), m_engine(engine)
+Profiler::Profiler(QV4::ExecutionEngine *engine) : featuresEnabled(0), m_engine(engine)
{
static int metatype = qRegisterMetaType<QList<QV4::Profiling::FunctionCallProperties> >();
static int metatype2 = qRegisterMetaType<QList<QV4::Profiling::MemoryAllocationProperties> >();
@@ -69,7 +69,7 @@ struct FunctionCallComparator {
void Profiler::stopProfiling()
{
- enabled = false;
+ featuresEnabled = 0;
reportData();
}
@@ -85,27 +85,29 @@ void Profiler::reportData()
emit dataReady(resolved, m_memory_data);
}
-void Profiler::startProfiling()
+void Profiler::startProfiling(quint64 features)
{
- if (!enabled) {
+ if (featuresEnabled == 0) {
m_data.clear();
m_memory_data.clear();
- qint64 timestamp = m_timer.nsecsElapsed();
- MemoryAllocationProperties heap = {timestamp,
- (qint64)m_engine->memoryManager->getAllocatedMem(),
- HeapPage};
- m_memory_data.append(heap);
- MemoryAllocationProperties small = {timestamp,
- (qint64)m_engine->memoryManager->getUsedMem(),
- SmallItem};
- m_memory_data.append(small);
- MemoryAllocationProperties large = {timestamp,
- (qint64)m_engine->memoryManager->getLargeItemsMem(),
- LargeItem};
- m_memory_data.append(large);
+ if (features & (1 << FeatureMemoryAllocation)) {
+ qint64 timestamp = m_timer.nsecsElapsed();
+ MemoryAllocationProperties heap = {timestamp,
+ (qint64)m_engine->memoryManager->getAllocatedMem(),
+ HeapPage};
+ m_memory_data.append(heap);
+ MemoryAllocationProperties small = {timestamp,
+ (qint64)m_engine->memoryManager->getUsedMem(),
+ SmallItem};
+ m_memory_data.append(small);
+ MemoryAllocationProperties large = {timestamp,
+ (qint64)m_engine->memoryManager->getLargeItemsMem(),
+ LargeItem};
+ m_memory_data.append(large);
+ }
- enabled = true;
+ featuresEnabled = features;
}
}
diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h
index f115137c86..8224f8a851 100644
--- a/src/qml/jsruntime/qv4profiling_p.h
+++ b/src/qml/jsruntime/qv4profiling_p.h
@@ -46,6 +46,11 @@ namespace QV4 {
namespace Profiling {
+enum Features {
+ FeatureFunctionCall,
+ FeatureMemoryAllocation
+};
+
enum MemoryType {
HeapPage,
LargeItem,
@@ -106,15 +111,18 @@ private:
};
#define Q_V4_PROFILE_ALLOC(engine, size, type)\
- (engine->profiler && engine->profiler->enabled ?\
+ (engine->profiler &&\
+ (engine->profiler->featuresEnabled & (1 << Profiling::FeatureMemoryAllocation)) ?\
engine->profiler->trackAlloc(size, type) : size)
#define Q_V4_PROFILE_DEALLOC(engine, pointer, size, type) \
- (engine->profiler && engine->profiler->enabled ?\
+ (engine->profiler &&\
+ (engine->profiler->featuresEnabled & (1 << Profiling::FeatureMemoryAllocation)) ?\
engine->profiler->trackDealloc(pointer, size, type) : pointer)
#define Q_V4_PROFILE(engine, ctx, function)\
- ((engine->profiler && engine->profiler->enabled) ?\
+ (engine->profiler &&\
+ (engine->profiler->featuresEnabled & (1 << Profiling::FeatureFunctionCall)) ?\
Profiling::FunctionCallProfiler::profileCall(engine->profiler, ctx, function) :\
function->code(ctx, function->codeData))
@@ -138,11 +146,11 @@ public:
return pointer;
}
- bool enabled;
+ quint64 featuresEnabled;
public slots:
void stopProfiling();
- void startProfiling();
+ void startProfiling(quint64 features);
void reportData();
void setTimer(const QElapsedTimer &timer) { m_timer = timer; }
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index ff51ee6c6f..32379f7f1e 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -1665,17 +1665,13 @@ void CallArgument::fromValue(int callType, QV8Engine *engine, const QV4::ValueRe
type = -1;
QQmlEnginePrivate *ep = engine->engine() ? QQmlEnginePrivate::get(engine->engine()) : 0;
- QVariant v = engine->toVariant(value, -1); // why -1 instead of callType?
+ QVariant v = engine->toVariant(value, callType);
if (v.userType() == callType) {
*qvariantPtr = v;
} else if (v.canConvert(callType)) {
*qvariantPtr = v;
qvariantPtr->convert(callType);
- } else if (QV4::SequencePrototype::isSequenceType(callType) && v.userType() == qMetaTypeId<QVariantList>()) {
- // convert the JS array to a sequence of the correct type.
- QVariant seqV = engine->toVariant(value, callType);
- *qvariantPtr = seqV;
} else {
QQmlMetaObject mo = ep ? ep->rawMetaObjectForType(callType) : QQmlMetaObject();
if (!mo.isNull()) {
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index a4378cf49a..8e91c0e6a5 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -320,7 +320,7 @@ QV4::CompiledData::CompilationUnit *Script::precompile(IR::Module *module, Compi
QQmlJS::Engine ee;
QQmlJS::Lexer lexer(&ee);
- lexer.setCode(source, /*line*/1, /*qml mode*/true);
+ lexer.setCode(source, /*line*/1, /*qml mode*/false);
QQmlJS::Parser parser(&ee);
parser.parseProgram();
diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp
index 63a8e93878..bd8a5ffccb 100644
--- a/src/qml/jsruntime/qv4string.cpp
+++ b/src/qml/jsruntime/qv4string.cpp
@@ -119,7 +119,7 @@ const ObjectVTable String::static_vtbl =
void String::destroy(Managed *that)
{
- static_cast<String*>(that)->~String();
+ static_cast<String*>(that)->d()->~Data();
}
void String::markObjects(Managed *that, ExecutionEngine *e)
diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp
index 34657501e8..68b08fb3ca 100644
--- a/src/qml/jsruntime/qv4variantobject.cpp
+++ b/src/qml/jsruntime/qv4variantobject.cpp
@@ -59,7 +59,7 @@ VariantObject::Data::Data(ExecutionEngine *engine, const QVariant &value)
QVariant VariantObject::toVariant(const QV4::ValueRef v)
{
if (v->asObject())
- return v->engine()->v8Engine->variantFromJS(v);
+ return v->engine()->v8Engine->toVariant(v, /*typeHint*/ -1, /*createJSValueForObjects*/ false);
if (v->isString())
return QVariant(v->stringValue()->toQString());
diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp
index 397b4851cf..b3d7bddff7 100644
--- a/src/qml/qml/ftw/qqmlthread.cpp
+++ b/src/qml/qml/ftw/qqmlthread.cpp
@@ -139,6 +139,7 @@ void QQmlThreadPrivate::run()
q->startupThread();
exec();
+ q->shutdownThread();
}
void QQmlThreadPrivate::mainEvent()
@@ -177,7 +178,6 @@ void QQmlThreadPrivate::threadEvent()
quit();
wakeOne();
unlock();
- q->shutdownThread();
return;
} else if (!threadList.isEmpty()) {
@@ -207,12 +207,6 @@ void QQmlThreadPrivate::threadEvent()
QQmlThread::QQmlThread()
: d(new QQmlThreadPrivate(this))
{
- d->lock();
- d->start();
- d->wait();
- d->unlock();
- d->moveToThread(d);
-
}
QQmlThread::~QQmlThread()
@@ -220,13 +214,29 @@ QQmlThread::~QQmlThread()
delete d;
}
+void QQmlThread::startup()
+{
+ d->lock();
+ d->start();
+ d->wait();
+ d->unlock();
+ d->moveToThread(d);
+}
+
void QQmlThread::shutdown()
{
d->lock();
Q_ASSERT(!d->m_shutdown);
d->m_shutdown = true;
if (d->threadList.isEmpty() && d->m_threadProcessing == false) {
- d->triggerThreadEvent();
+ if (QCoreApplication::closingDown()) {
+ d->quit();
+ d->unlock();
+ d->QThread::wait();
+ return;
+ } else {
+ d->triggerThreadEvent();
+ }
} else if (d->mainSync) {
d->wakeOne();
}
diff --git a/src/qml/qml/ftw/qqmlthread_p.h b/src/qml/qml/ftw/qqmlthread_p.h
index 995fcd4824..95d32d4fd2 100644
--- a/src/qml/qml/ftw/qqmlthread_p.h
+++ b/src/qml/qml/ftw/qqmlthread_p.h
@@ -60,6 +60,8 @@ class QQmlThread
public:
QQmlThread();
virtual ~QQmlThread();
+
+ void startup();
void shutdown();
bool isShutdown() const;
diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp
index 56eddfa478..9ccaee7cd7 100644
--- a/src/qml/qml/qqmlapplicationengine.cpp
+++ b/src/qml/qml/qqmlapplicationengine.cpp
@@ -65,7 +65,8 @@ void QQmlApplicationEnginePrivate::init()
q->connect(q, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit()));
#ifndef QT_NO_TRANSLATION
QTranslator* qtTranslator = new QTranslator;
- if (qtTranslator->load(QLatin1String("qt_") + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
+ QLocale locale;
+ if (qtTranslator->load(locale, QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
QCoreApplication::installTranslator(qtTranslator);
translators << qtTranslator;
#endif
@@ -82,7 +83,8 @@ void QQmlApplicationEnginePrivate::loadTranslations(const QUrl &rootFile)
QFileInfo fi(rootFile.toLocalFile());
QTranslator *translator = new QTranslator;
- if (translator->load(QLatin1String("qml_") + QLocale::system().name(), fi.path() + QLatin1String("/i18n"))) {
+ QLocale locale;
+ if (translator->load(locale, QLatin1String("qml"), QLatin1String("_"), fi.path() + QLatin1String("/i18n"))) {
QCoreApplication::installTranslator(translator);
translators << translator;
} else {
@@ -160,6 +162,10 @@ void QQmlApplicationEnginePrivate::_q_finishLoad(QObject *o)
}
\endcode
+ Unlike QQuickView, QQmlApplicationEngine does not automatically create a root
+ window. If you are using visual items from Qt Quick, you will need to place
+ them inside of a \l [QML] {Window}.
+
You can also use QCoreApplication with QQmlApplicationEngine, if you are not using any QML modules which require a QGuiApplication (such as \c QtQuick).
List of configuration changes from a default QQmlEngine:
@@ -167,7 +173,7 @@ void QQmlApplicationEnginePrivate::_q_finishLoad(QObject *o)
\list
\li Connecting Qt.quit() to QCoreApplication::quit()
\li Automatically loads translation files from an i18n directory adjacent to the main QML file.
- \li Automatically sets an incubuation controller if the scene contains a QQuickWindow.
+ \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.
\endlist
diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qml/qqmldirparser.cpp
index 7068818f15..83e1c9c757 100644
--- a/src/qml/qml/qqmldirparser.cpp
+++ b/src/qml/qml/qqmldirparser.cpp
@@ -231,6 +231,28 @@ bool QQmlDirParser::parse(const QString &source)
reportError(lineNumber, 0, QString::fromLatin1("designersupported does not expect any argument"));
else
_designerSupported = true;
+ } else if (sections[0] == QLatin1String("depends")) {
+ if (sectionCount != 3) {
+ reportError(lineNumber, 0,
+ QString::fromLatin1("depends requires 2 arguments, but %1 were provided").arg(sectionCount - 1));
+ continue;
+ }
+
+ const QString &version = sections[2];
+ const int dotIndex = version.indexOf(QLatin1Char('.'));
+ bool validVersionNumber = false;
+ const int majorVersion = parseInt(QStringRef(&version, 0, dotIndex), &validVersionNumber);
+ if (validVersionNumber) {
+ const int minorVersion = parseInt(QStringRef(&version, dotIndex+1, version.length()-dotIndex-1), &validVersionNumber);
+
+ if (validVersionNumber) {
+ Component entry(sections[1], QString(), majorVersion, minorVersion);
+ entry.internal = true;
+ _dependencies.insert(entry.typeName, entry);
+ }
+ } else {
+ reportError(lineNumber, 0, QString(QLatin1String("invalid version %1")).arg(version));
+ }
} else if (sectionCount == 2) {
// No version specified (should only be used for relative qmldir files)
const Component entry(sections[0], sections[1], -1, -1);
@@ -348,6 +370,11 @@ QHash<QString, QQmlDirParser::Component> QQmlDirParser::components() const
return _components;
}
+QHash<QString, QQmlDirParser::Component> QQmlDirParser::dependencies() const
+{
+ return _dependencies;
+}
+
QList<QQmlDirParser::Script> QQmlDirParser::scripts() const
{
return _scripts;
diff --git a/src/qml/qml/qqmldirparser_p.h b/src/qml/qml/qqmldirparser_p.h
index 54843a13b0..bbe61dfb96 100644
--- a/src/qml/qml/qqmldirparser_p.h
+++ b/src/qml/qml/qqmldirparser_p.h
@@ -119,6 +119,7 @@ public:
};
QHash<QString,Component> components() const;
+ QHash<QString,Component> dependencies() const;
QList<Script> scripts() const;
QList<Plugin> plugins() const;
bool designerSupported() const;
@@ -137,12 +138,14 @@ public:
#endif
private:
+ bool maybeAddComponent(const QString &typeName, const QString &fileName, const QString &version, QHash<QString,Component> &hash, int lineNumber = -1, bool multi = true);
void reportError(quint16 line, quint16 column, const QString &message);
private:
QList<QQmlJS::DiagnosticMessage> _errors;
QString _typeNamespace;
QHash<QString,Component> _components; // multi hash
+ QHash<QString,Component> _dependencies;
QList<Script> _scripts;
QList<Plugin> _plugins;
bool _designerSupported;
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index e54e23813d..2b69661c4b 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -1247,42 +1247,38 @@ void QQmlEngine::setContextForObject(QObject *object, QQmlContext *context)
/*!
\enum QQmlEngine::ObjectOwnership
- Ownership controls whether or not QML automatically destroys the
- QObject when the object is garbage collected by the JavaScript
- engine. The two ownership options are:
-
- \value CppOwnership The object is owned by C++ code, and will
- never be deleted by QML. The JavaScript destroy() method cannot be
- used on objects with CppOwnership. This option is similar to
- QScriptEngine::QtOwnership.
-
- \value JavaScriptOwnership The object is owned by JavaScript.
- When the object is returned to QML as the return value of a method
- call or property access, QML will track it, and delete the object
- if there are no remaining JavaScript references to it and it has no
- QObject::parent(). An object tracked by one QQmlEngine
- will be deleted during that QQmlEngine's destructor, and thus
- JavaScript references between objects with JavaScriptOwnership from
- two different engines will not be valid after the deletion of one of
- those engines. This option is similar to QScriptEngine::ScriptOwnership.
+ ObjectOwnership controls whether or not QML automatically destroys the
+ QObject when the corresponding JavaScript object is garbage collected by the
+ engine. The two ownership options are:
+
+ \value CppOwnership The object is owned by C++ code and QML will never delete
+ it. The JavaScript destroy() method cannot be used on these objects. This
+ option is similar to QScriptEngine::QtOwnership.
+
+ \value JavaScriptOwnership The object is owned by JavaScript. When the object
+ is returned to QML as the return value of a method call, QML will track it
+ and delete it if there are no remaining JavaScript references to it and
+ it has no QObject::parent(). An object tracked by one QQmlEngine will be
+ deleted during that QQmlEngine's destructor. Thus, JavaScript references
+ between objects with JavaScriptOwnership from two different engines will
+ not be valid if one of these engines is deleted. This option is similar to
+ QScriptEngine::ScriptOwnership.
Generally an application doesn't need to set an object's ownership
- explicitly. QML uses a heuristic to set the default object
- ownership. By default, an object that is created by QML has
- JavaScriptOwnership. The exception to this are the root objects
- created by calling QQmlComponent::create() or
- QQmlComponent::beginCreate() which have CppOwnership by
- default. The ownership of these root-level objects is considered to
- have been transferred to the C++ caller.
-
- Objects not-created by QML have CppOwnership by default. The
- exception to this is objects returned from C++ method calls; in these cases,
- the ownership of the returned objects will be set to JavaScriptOwnerShip.
- Note this applies only to explicit invocations of Q_INVOKABLE methods or slots,
- and not to property getter invocations.
-
- Calling setObjectOwnership() overrides the default ownership
- heuristic used by QML.
+ explicitly. QML uses a heuristic to set the default ownership. By default, an
+ object that is created by QML has JavaScriptOwnership. The exception to this
+ are the root objects created by calling QQmlComponent::create() or
+ QQmlComponent::beginCreate(), which have CppOwnership by default. The
+ ownership of these root-level objects is considered to have been transferred
+ to the C++ caller.
+
+ Objects not-created by QML have CppOwnership by default. The exception to this
+ are objects returned from C++ method calls; their ownership will be set to
+ JavaScriptOwnership. This applies only to explicit invocations of Q_INVOKABLE
+ methods or slots, but not to property getter invocations.
+
+ Calling setObjectOwnership() overrides the default ownership heuristic used by
+ QML.
*/
/*!
diff --git a/src/qml/qml/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp
index d84a7804f4..e48224333c 100644
--- a/src/qml/qml/qqmlextensionplugin.cpp
+++ b/src/qml/qml/qqmlextensionplugin.cpp
@@ -63,7 +63,7 @@ QT_BEGIN_NAMESPACE
or other issues in the library user's code.
- \section1 An example
+ \section1 An Example
Suppose there is a new \c TimeModel C++ class that should be made available
as a new QML element. It provides the current time through \c hour and \c minute
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index c09ab69424..d20fe72d09 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -98,7 +98,7 @@ struct QQmlMetaTypeData
QBitArray lists;
QList<QQmlPrivate::AutoParentFunction> parentFunctions;
- QQmlPrivate::QmlUnitCacheLookupFunction lookupCachedQmlUnit;
+ QVector<QQmlPrivate::QmlUnitCacheLookupFunction> lookupCachedQmlUnit;
QSet<QString> protectedNamespaces;
@@ -135,7 +135,6 @@ static uint qHash(const QQmlMetaTypeData::VersionedUri &v)
}
QQmlMetaTypeData::QQmlMetaTypeData()
- : lookupCachedQmlUnit(0)
{
}
@@ -1347,7 +1346,7 @@ int registerQmlUnitCacheHook(const QQmlPrivate::RegisterQmlUnitCacheHook &hookRe
qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
QWriteLocker lock(metaTypeDataLock());
QQmlMetaTypeData *data = metaTypeData();
- data->lookupCachedQmlUnit = hookRegistration.lookupCachedQmlUnit;
+ data->lookupCachedQmlUnit << hookRegistration.lookupCachedQmlUnit;
return 0;
}
@@ -1877,8 +1876,11 @@ const QQmlPrivate::CachedQmlUnit *QQmlMetaType::findCachedCompilationUnit(const
{
QReadLocker lock(metaTypeDataLock());
QQmlMetaTypeData *data = metaTypeData();
- if (data->lookupCachedQmlUnit)
- return data->lookupCachedQmlUnit(uri);
+ for (QVector<QQmlPrivate::QmlUnitCacheLookupFunction>::ConstIterator it = data->lookupCachedQmlUnit.constBegin(), end = data->lookupCachedQmlUnit.constEnd();
+ it != end; ++it) {
+ if (const QQmlPrivate::CachedQmlUnit *unit = (*it)(uri))
+ return unit;
+ }
return 0;
}
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 0ad60e01ab..a827e96ab1 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -93,7 +93,7 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile
sharedState->rootContext = 0;
QQmlProfiler *profiler = QQmlEnginePrivate::get(engine)->profiler;
- Q_QML_PROFILE_IF_ENABLED(profiler,
+ Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler,
sharedState->profiler.init(profiler, compiledData->totalParserStatusCount));
}
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index 42bf0dd657..09b735ae9e 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -1585,11 +1585,14 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object,
propertyType = propertyMetaObject.className();
}
} else if (value.userType() != QVariant::Invalid) {
- valueType = QMetaType::typeName(value.userType());
+ if (value.userType() == QMetaType::VoidStar)
+ valueType = "null";
+ else
+ valueType = QMetaType::typeName(value.userType());
}
if (!valueType)
- valueType = "null";
+ valueType = "undefined";
if (!propertyType)
propertyType = QMetaType::typeName(type);
if (!propertyType)
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 0b7cc8e911..0e2d4d027a 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -728,6 +728,8 @@ void QQmlDataBlob::ThreadData::setProgress(quint8 v)
QQmlDataLoaderThread::QQmlDataLoaderThread(QQmlDataLoader *loader)
: m_loader(loader), m_networkAccessManager(0), m_networkReplyProxy(0)
{
+ // Do that after initializing all the members.
+ startup();
}
QNetworkAccessManager *QQmlDataLoaderThread::networkAccessManager() const
diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp
index 35d31e4f1f..39b816f97c 100644
--- a/src/qml/qml/v8/qv8engine.cpp
+++ b/src/qml/qml/v8/qv8engine.cpp
@@ -79,6 +79,41 @@ Q_DECLARE_METATYPE(QList<int>)
// QQmlEngine is not available
QT_BEGIN_NAMESPACE
+template <typename ReturnType>
+ReturnType convertJSValueToVariantType(const QJSValue &value)
+{
+ return value.toVariant().value<ReturnType>();
+}
+
+static void saveJSValue(QDataStream &stream, const void *data)
+{
+ const QJSValue *jsv = reinterpret_cast<const QJSValue *>(data);
+ quint32 isNullOrUndefined = 0;
+ if (jsv->isNull())
+ isNullOrUndefined |= 0x1;
+ if (jsv->isUndefined())
+ isNullOrUndefined |= 0x2;
+ stream << isNullOrUndefined;
+ if (!isNullOrUndefined)
+ reinterpret_cast<const QJSValue*>(data)->toVariant().save(stream);
+}
+
+static void restoreJSValue(QDataStream &stream, void *data)
+{
+ QJSValue *jsv = reinterpret_cast<QJSValue*>(data);
+ QJSValuePrivate *d = QJSValuePrivate::get(*jsv);
+
+ quint32 isNullOrUndefined;
+ stream >> isNullOrUndefined;
+ if (isNullOrUndefined & 0x1) {
+ d->value = QV4::Primitive::nullValue().asReturnedValue();
+ } else if (isNullOrUndefined & 0x2) {
+ d->value = QV4::Primitive::undefinedValue().asReturnedValue();
+ } else {
+ d->value = QV4::Primitive::emptyValue().asReturnedValue();
+ d->unboundData.load(stream);
+ }
+}
QV8Engine::QV8Engine(QJSEngine* qq)
: q(qq)
@@ -96,6 +131,14 @@ QV8Engine::QV8Engine(QJSEngine* qq)
qMetaTypeId<QJSValue>();
qMetaTypeId<QList<int> >();
+ if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QVariantMap>())
+ QMetaType::registerConverter<QJSValue, QVariantMap>(convertJSValueToVariantType<QVariantMap>);
+ if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QVariantList>())
+ QMetaType::registerConverter<QJSValue, QVariantList>(convertJSValueToVariantType<QVariantList>);
+ if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QStringList>())
+ QMetaType::registerConverter<QJSValue, QStringList>(convertJSValueToVariantType<QStringList>);
+ QMetaType::registerStreamOperators(qMetaTypeId<QJSValue>(), saveJSValue, restoreJSValue);
+
m_v4Engine = new QV4::ExecutionEngine;
m_v4Engine->v8Engine = this;
@@ -116,7 +159,7 @@ QV8Engine::~QV8Engine()
delete m_v4Engine;
}
-QVariant QV8Engine::toVariant(const QV4::ValueRef value, int typeHint)
+QVariant QV8Engine::toVariant(const QV4::ValueRef value, int typeHint, bool createJSValueForObjects, V8ObjectSet *visitedObjects)
{
Q_ASSERT (!value->isEmpty());
QV4::Scope scope(m_v4Engine);
@@ -178,7 +221,88 @@ QVariant QV8Engine::toVariant(const QV4::ValueRef value, int typeHint)
return retn;
}
- return toBasicVariant(value);
+ if (value->isUndefined())
+ return QVariant();
+ if (value->isNull())
+ return QVariant(QMetaType::VoidStar, (void *)0);
+ if (value->isBoolean())
+ return value->booleanValue();
+ if (value->isInteger())
+ return value->integerValue();
+ if (value->isNumber())
+ return value->asDouble();
+ if (value->isString())
+ return value->stringValue()->toQString();
+ if (QQmlLocaleData *ld = value->as<QQmlLocaleData>())
+ return ld->d()->locale;
+ if (QV4::DateObject *d = value->asDateObject())
+ return d->toQDateTime();
+ // NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)!
+
+ QV4::ScopedObject o(scope, value);
+ Q_ASSERT(o);
+
+ if (QV4::RegExpObject *re = o->as<QV4::RegExpObject>())
+ return re->toQRegExp();
+
+ if (createJSValueForObjects)
+ return QVariant::fromValue(QJSValue(new QJSValuePrivate(o->asReturnedValue())));
+
+ return objectToVariant(o, visitedObjects);
+}
+
+QVariant QV8Engine::objectToVariant(QV4::Object *o, V8ObjectSet *visitedObjects)
+{
+ Q_ASSERT(o);
+
+ V8ObjectSet recursionGuardSet;
+ if (!visitedObjects) {
+ visitedObjects = &recursionGuardSet;
+ } else if (visitedObjects->contains(o)) {
+ // Avoid recursion.
+ // For compatibility with QVariant{List,Map} conversion, we return an
+ // empty object (and no error is thrown).
+ if (o->asArrayObject())
+ return QVariantList();
+ return QVariantMap();
+ }
+ visitedObjects->insert(o);
+
+ QVariant result;
+
+ if (o->asArrayObject()) {
+ QV4::Scope scope(m_v4Engine);
+ QV4::ScopedArrayObject a(scope, o->asReturnedValue());
+ QV4::ScopedValue v(scope);
+ QVariantList list;
+
+ int length = a->getLength();
+ for (int ii = 0; ii < length; ++ii) {
+ v = a->getIndexed(ii);
+ list << toVariant(v, -1, /*createJSValueForObjects*/false, visitedObjects);
+ }
+
+ result = list;
+ } else if (!o->asFunctionObject()) {
+ QVariantMap map;
+ QV4::Scope scope(m_v4Engine);
+ QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly);
+ QV4::ScopedValue name(scope);
+ QV4::ScopedValue val(scope);
+ while (1) {
+ name = it.nextPropertyNameAsString(val);
+ if (name->isNull())
+ break;
+
+ QString key = name->toQStringNoThrow();
+ map.insert(key, toVariant(val, /*type hint*/-1, /*createJSValueForObjects*/false, visitedObjects));
+ }
+
+ result = map;
+ }
+
+ visitedObjects->remove(o);
+ return result;
}
static QV4::ReturnedValue arrayFromStringList(QV8Engine *engine, const QStringList &list)
@@ -240,6 +364,8 @@ QV4::ReturnedValue QV8Engine::fromVariant(const QVariant &variant)
case QMetaType::UnknownType:
case QMetaType::Void:
return QV4::Encode::undefined();
+ case QMetaType::VoidStar:
+ return QV4::Encode::null();
case QMetaType::Bool:
return QV4::Encode(*reinterpret_cast<const bool*>(ptr));
case QMetaType::Int:
@@ -368,59 +494,6 @@ QQmlContextData *QV8Engine::callingContext()
return QV4::QmlContextWrapper::callingContext(m_v4Engine);
}
-// Converts a JS value to a QVariant.
-// Null, Undefined -> QVariant() (invalid)
-// Boolean -> QVariant(bool)
-// Number -> QVariant(double)
-// String -> QVariant(QString)
-// Array -> QVariantList(...)
-// Date -> QVariant(QDateTime)
-// RegExp -> QVariant(QRegExp)
-// [Any other object] -> QVariantMap(...)
-QVariant QV8Engine::toBasicVariant(const QV4::ValueRef value)
-{
- if (value->isNullOrUndefined())
- return QVariant();
- if (value->isBoolean())
- return value->booleanValue();
- if (value->isInteger())
- return value->integerValue();
- if (value->isNumber())
- return value->asDouble();
- if (value->isString())
- return value->stringValue()->toQString();
- if (QQmlLocaleData *ld = value->as<QQmlLocaleData>())
- return ld->d()->locale;
- if (QV4::DateObject *d = value->asDateObject())
- return d->toQDateTime();
- // NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)!
-
- QV4::Scope scope(value->engine());
- QV4::ScopedObject o(scope, value);
- Q_ASSERT(o);
-
- if (QV4::RegExpObject *re = o->as<QV4::RegExpObject>())
- return re->toQRegExp();
- if (o->asArrayObject()) {
- QV4::ScopedArrayObject a(scope, o);
- QV4::ScopedValue v(scope);
- QVariantList rv;
-
- int length = a->getLength();
- for (int ii = 0; ii < length; ++ii) {
- v = a->getIndexed(ii);
- rv << toVariant(v, -1);
- }
- return rv;
- }
- if (!value->asFunctionObject())
- return variantMapFromJS(o);
-
- return QVariant();
-}
-
-
-
void QV8Engine::initializeGlobal()
{
QV4::Scope scope(m_v4Engine);
@@ -543,36 +616,6 @@ QV4::ReturnedValue QV8Engine::variantListToJS(const QVariantList &lst)
return a.asReturnedValue();
}
-// Converts a JS Array object to a QVariantList.
-// The result is a QVariantList with length equal to the length
-// of the JS Array, and elements being the JS Array's elements
-// converted to QVariants, recursively.
-QVariantList QV8Engine::variantListFromJS(QV4::ArrayObject *a, V8ObjectSet &visitedObjects)
-{
- QVariantList result;
- if (!a)
- return result;
-
- if (visitedObjects.contains(a))
- // Avoid recursion.
- return result;
-
- visitedObjects.insert(a);
-
- QV4::Scope scope(a->engine());
- QV4::ScopedValue v(scope);
-
- quint32 length = a->getLength();
- for (quint32 i = 0; i < length; ++i) {
- v = a->getIndexed(i);
- result.append(variantFromJS(v, visitedObjects));
- }
-
- visitedObjects.remove(a);
-
- return result;
-}
-
// Converts a QVariantMap to JS.
// The result is a new Object object with property names being
// the keys of the QVariantMap, and values being the values of
@@ -596,43 +639,6 @@ QV4::ReturnedValue QV8Engine::variantMapToJS(const QVariantMap &vmap)
return o.asReturnedValue();
}
-// Converts a JS Object to a QVariantMap.
-// The result is a QVariantMap with keys being the property names
-// of the object, and values being the values of the JS object's
-// properties converted to QVariants, recursively.
-QVariantMap QV8Engine::variantMapFromJS(QV4::Object *o, V8ObjectSet &visitedObjects)
-{
- QVariantMap result;
-
- if (!o || o->asFunctionObject())
- return result;
-
- if (visitedObjects.contains(o)) {
- // Avoid recursion.
- // For compatibility with QVariant{List,Map} conversion, we return an
- // empty object (and no error is thrown).
- return result;
- }
- QV4::Scope scope(o->engine());
-
- visitedObjects.insert(o);
-
- QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly);
- QV4::ScopedValue name(scope);
- QV4::ScopedValue val(scope);
- while (1) {
- name = it.nextPropertyNameAsString(val);
- if (name->isNull())
- break;
-
- QString key = name->toQStringNoThrow();
- result.insert(key, variantFromJS(val, visitedObjects));
- }
-
- visitedObjects.remove(o);
- return result;
-}
-
// Converts the meta-type defined by the given type and data to JS.
// Returns the value if conversion succeeded, an empty handle otherwise.
QV4::ReturnedValue QV8Engine::metaTypeToJS(int type, const void *data)
@@ -644,6 +650,8 @@ QV4::ReturnedValue QV8Engine::metaTypeToJS(int type, const void *data)
case QMetaType::UnknownType:
case QMetaType::Void:
return QV4::Encode::undefined();
+ case QMetaType::VoidStar:
+ return QV4::Encode::null();
case QMetaType::Bool:
return QV4::Encode(*reinterpret_cast<const bool*>(data));
case QMetaType::Int:
@@ -805,7 +813,7 @@ bool QV8Engine::metaTypeFromJS(const QV4::ValueRef value, int type, void *data)
case QMetaType::QVariantList: {
QV4::ScopedArrayObject a(scope, value);
if (a) {
- *reinterpret_cast<QVariantList *>(data) = variantListFromJS(a);
+ *reinterpret_cast<QVariantList *>(data) = toVariant(a, /*typeHint*/-1, /*createJSValueForObjects*/false).toList();
return true;
}
break;
@@ -819,7 +827,7 @@ bool QV8Engine::metaTypeFromJS(const QV4::ValueRef value, int type, void *data)
break;
}
case QMetaType::QVariant:
- *reinterpret_cast<QVariant*>(data) = variantFromJS(value);
+ *reinterpret_cast<QVariant*>(data) = toVariant(value, /*typeHint*/-1, /*createJSValueForObjects*/false);
return true;
case QMetaType::QJsonValue:
*reinterpret_cast<QJsonValue *>(data) = QV4::JsonObject::toJsonValue(value);
@@ -915,55 +923,6 @@ QV4::ReturnedValue QV8Engine::variantToJS(const QVariant &value)
return metaTypeToJS(value.userType(), value.constData());
}
-// Converts a JS value to a QVariant.
-// Undefined -> QVariant() (invalid)
-// Null -> QVariant((void*)0)
-// Boolean -> QVariant(bool)
-// Number -> QVariant(double)
-// String -> QVariant(QString)
-// Array -> QVariantList(...)
-// Date -> QVariant(QDateTime)
-// RegExp -> QVariant(QRegExp)
-// [Any other object] -> QVariantMap(...)
-QVariant QV8Engine::variantFromJS(const QV4::ValueRef value,
- V8ObjectSet &visitedObjects)
-{
- Q_ASSERT(!value->isEmpty());
- if (value->isUndefined())
- return QVariant();
- if (value->isNull())
- return QVariant(QMetaType::VoidStar, 0);
- if (value->isBoolean())
- return value->booleanValue();
- if (value->isInteger())
- return value->integerValue();
- if (value->isNumber())
- return value->asDouble();
- if (value->isString())
- return value->stringValue()->toQString();
-
- Q_ASSERT(value->isObject());
- QV4::Scope scope(value->engine());
-
- if (value->asArrayObject()) {
- QV4::ScopedArrayObject a(scope, value);
- return variantListFromJS(a, visitedObjects);
- }
- if (QV4::DateObject *d = value->asDateObject())
- return d->toQDateTime();
- if (QV4::RegExpObject *re = value->as<QV4::RegExpObject>())
- return re->toQRegExp();
- if (QV4::VariantObject *v = value->as<QV4::VariantObject>())
- return v->d()->data;
- if (value->as<QV4::QObjectWrapper>())
- return qVariantFromValue(qtObjectFromJS(value));
- if (QV4::QmlValueTypeWrapper *v = value->as<QV4::QmlValueTypeWrapper>())
- return v->toVariant();
- QV4::ScopedObject o(scope, value);
- return variantMapFromJS(o, visitedObjects);
-}
-
-
bool QV8Engine::convertToNativeQObject(const QV4::ValueRef value, const QByteArray &targetType, void **result)
{
if (!targetType.endsWith('*'))
diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h
index e2c96ffc87..51e857c8a2 100644
--- a/src/qml/qml/v8/qv8engine_p.h
+++ b/src/qml/qml/v8/qv8engine_p.h
@@ -197,9 +197,13 @@ public:
void freezeObject(const QV4::ValueRef value);
- QVariant toVariant(const QV4::ValueRef value, int typeHint);
+ QVariant toVariant(const QV4::ValueRef value, int typeHint, bool createJSValueForObjects = true, V8ObjectSet *visitedObjects = 0);
+ QVariant objectToVariant(QV4::Object *o, V8ObjectSet *visitedObjects = 0);
QV4::ReturnedValue fromVariant(const QVariant &);
+ QVariantMap variantMapFromJS(QV4::Object *o)
+ { return objectToVariant(o).toMap(); }
+
// Return a JS string for the given QString \a string
QV4::ReturnedValue toString(const QString &string);
@@ -218,16 +222,8 @@ public:
void setExtensionData(int, Deletable *);
QV4::ReturnedValue variantListToJS(const QVariantList &lst);
- inline QVariantList variantListFromJS(QV4::ArrayObject *array)
- { V8ObjectSet visitedObjects; return variantListFromJS(array, visitedObjects); }
-
QV4::ReturnedValue variantMapToJS(const QVariantMap &vmap);
- inline QVariantMap variantMapFromJS(QV4::Object *object)
- { V8ObjectSet visitedObjects; return variantMapFromJS(object, visitedObjects); }
-
QV4::ReturnedValue variantToJS(const QVariant &value);
- inline QVariant variantFromJS(const QV4::ValueRef value)
- { V8ObjectSet visitedObjects; return variantFromJS(value, visitedObjects); }
QV4::ReturnedValue metaTypeToJS(int type, const void *data);
bool metaTypeFromJS(const QV4::ValueRef value, int type, void *data);
@@ -265,15 +261,9 @@ protected:
QHash<QString, quint32> m_consoleCount;
- QVariant toBasicVariant(const QV4::ValueRef);
-
void initializeGlobal();
private:
- QVariantList variantListFromJS(QV4::ArrayObject *array, V8ObjectSet &visitedObjects);
- QVariantMap variantMapFromJS(QV4::Object *object, V8ObjectSet &visitedObjects);
- QVariant variantFromJS(const QV4::ValueRef value, V8ObjectSet &visitedObjects);
-
Q_DISABLE_COPY(QV8Engine)
};
diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp
index 602e5cf14e..9ba610b9ba 100644
--- a/src/qml/types/qqmlbind.cpp
+++ b/src/qml/types/qqmlbind.cpp
@@ -72,7 +72,7 @@ public:
\ingroup qtquick-interceptors
\brief Enables the arbitrary creation of property bindings
- \section1 Binding to an inaccessible property
+ \section1 Binding to an Inaccessible Property
Sometimes it is necessary to bind to a property of an object that wasn't
directly instantiated by QML - generally a property of a class exported
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
index 25879972ca..142625d7ae 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qml/types/qqmllistmodel.cpp
@@ -1330,6 +1330,11 @@ void DynamicRoleModelNode::updateValues(const QVariantMap &object, QVector<int>
QVariant value = object[key];
+ // A JS array/object is translated into a (hierarchical) QQmlListModel,
+ // so translate to a variant map/list first with toVariant().
+ if (value.userType() == qMetaTypeId<QJSValue>())
+ value = value.value<QJSValue>().toVariant();
+
if (value.type() == QVariant::List) {
QQmlListModel *subModel = QQmlListModel::createWithOwner(m_owner);
@@ -1392,6 +1397,12 @@ void DynamicRoleModelNodeMetaObject::propertyWritten(int index)
QQmlListModel *parentModel = m_owner->m_owner;
QVariant v = value(index);
+
+ // A JS array/object is translated into a (hierarchical) QQmlListModel,
+ // so translate to a variant map/list first with toVariant().
+ if (v.userType() == qMetaTypeId<QJSValue>())
+ v= v.value<QJSValue>().toVariant();
+
if (v.type() == QVariant::List) {
QQmlListModel *subModel = QQmlListModel::createWithOwner(parentModel);
diff --git a/src/qml/types/qqmlobjectmodel.cpp b/src/qml/types/qqmlobjectmodel.cpp
index cdc8f2393f..d2f47c41b2 100644
--- a/src/qml/types/qqmlobjectmodel.cpp
+++ b/src/qml/types/qqmlobjectmodel.cpp
@@ -138,6 +138,7 @@ public:
The example below places three colored rectangles in a ListView.
\code
import QtQuick 2.0
+ import QtQml.Models 2.1
Rectangle {
ObjectModel {
diff --git a/src/qml/util/qqmllistaccessor.cpp b/src/qml/util/qqmllistaccessor.cpp
index e434d6cef4..5a199abf44 100644
--- a/src/qml/util/qqmllistaccessor.cpp
+++ b/src/qml/util/qqmllistaccessor.cpp
@@ -61,6 +61,11 @@ void QQmlListAccessor::setList(const QVariant &v, QQmlEngine *engine)
{
d = v;
+ // An incoming JS array as model is treated as a variant list, so we need to
+ // convert it first with toVariant().
+ if (d.userType() == qMetaTypeId<QJSValue>())
+ d = d.value<QJSValue>().toVariant();
+
QQmlEnginePrivate *enginePrivate = engine?QQmlEnginePrivate::get(engine):0;
if (!d.isValid()) {
@@ -73,7 +78,7 @@ void QQmlListAccessor::setList(const QVariant &v, QQmlEngine *engine)
m_type = Integer;
} else if ((!enginePrivate && QQmlMetaType::isQObject(d.userType())) ||
(enginePrivate && enginePrivate->isQObject(d.userType()))) {
- QObject *data = enginePrivate?enginePrivate->toQObject(v):QQmlMetaType::toQObject(v);
+ QObject *data = enginePrivate?enginePrivate->toQObject(d):QQmlMetaType::toQObject(d);
d = QVariant::fromValue(data);
m_type = Instance;
} else if (d.userType() == qMetaTypeId<QQmlListReference>()) {
diff --git a/src/quick/doc/images/qml-blending-layered.png b/src/quick/doc/images/qml-blending-layered.png
new file mode 100644
index 0000000000..fa1c24a98e
--- /dev/null
+++ b/src/quick/doc/images/qml-blending-layered.png
Binary files differ
diff --git a/src/quick/doc/images/qml-blending-nonlayered.png b/src/quick/doc/images/qml-blending-nonlayered.png
new file mode 100644
index 0000000000..265abf6530
--- /dev/null
+++ b/src/quick/doc/images/qml-blending-nonlayered.png
Binary files differ
diff --git a/src/quick/doc/images/qml-shadereffect-layereffect.png b/src/quick/doc/images/qml-shadereffect-layereffect.png
new file mode 100644
index 0000000000..44b05a9949
--- /dev/null
+++ b/src/quick/doc/images/qml-shadereffect-layereffect.png
Binary files differ
diff --git a/src/quick/doc/images/qml-shadereffect-nolayereffect.png b/src/quick/doc/images/qml-shadereffect-nolayereffect.png
new file mode 100644
index 0000000000..f21e3f0c4e
--- /dev/null
+++ b/src/quick/doc/images/qml-shadereffect-nolayereffect.png
Binary files differ
diff --git a/src/quick/doc/images/qml-shadereffect-opacitymask.png b/src/quick/doc/images/qml-shadereffect-opacitymask.png
new file mode 100644
index 0000000000..e056aa763b
--- /dev/null
+++ b/src/quick/doc/images/qml-shadereffect-opacitymask.png
Binary files differ
diff --git a/src/quick/doc/qtquick.qdocconf b/src/quick/doc/qtquick.qdocconf
index 5b8388f977..d54e5feecb 100644
--- a/src/quick/doc/qtquick.qdocconf
+++ b/src/quick/doc/qtquick.qdocconf
@@ -62,9 +62,9 @@ headerdirs += ../../plugins
sourcedirs += ../../plugins
#exclude certain directories
-excludedirs += ../../imports/dialogs \
- ../../imports/models \
- ../../../examples/quick/dialogs
+excludedirs += ../../imports/models
+
+examples.fileextensions += "*.qm"
manifestmeta.thumbnail.names += "QtQuick/Threaded ListModel Example"
diff --git a/src/quick/doc/snippets/qml/layerblending.qml b/src/quick/doc/snippets/qml/layerblending.qml
new file mode 100644
index 0000000000..0ef23465a5
--- /dev/null
+++ b/src/quick/doc/snippets/qml/layerblending.qml
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Gunnar Sletta <gunnar@sletta.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Item {
+ width: 300
+ height: 200
+
+ // The checkers background
+ ShaderEffect {
+ id: tileBackground
+ anchors.fill: parent
+
+ property real tileSize: 10
+ property color color1: Qt.rgba(0.9, 0.9, 0.9, 1);
+ property color color2: Qt.rgba(0.85, 0.85, 0.85, 1);
+
+ property size pixelSize: Qt.size(width / tileSize, height / tileSize);
+
+ fragmentShader:
+ "
+ uniform lowp vec4 color1;
+ uniform lowp vec4 color2;
+ uniform highp vec2 pixelSize;
+ varying highp vec2 qt_TexCoord0;
+ void main() {
+ highp vec2 tc = sign(sin(3.14152 * qt_TexCoord0 * pixelSize));
+ if (tc.x != tc.y)
+ gl_FragColor = color1;
+ else
+ gl_FragColor = color2;
+ }
+ "
+ }
+
+
+ Row {
+ height: 100
+ anchors.centerIn: parent
+ spacing: 50
+
+//! [non-layered]
+Item {
+ id: nonLayered
+
+ opacity: 0.5
+
+ width: 100
+ height: 100
+
+ Rectangle { width: 80; height: 80; border.width: 1 }
+ Rectangle { x: 20; y: 20; width: 80; height: 80; border.width: 1 }
+}
+//! [non-layered]
+
+//! [layered]
+Item {
+ id: layered
+
+ opacity: 0.5
+
+ layer.enabled: true
+
+ width: 100
+ height: 100
+
+ Rectangle { width: 80; height: 80; border.width: 1 }
+ Rectangle { x: 20; y: 20; width: 80; height: 80; border.width: 1 }
+}
+//! [layered]
+
+ }
+}
diff --git a/src/quick/doc/snippets/qml/layerwitheffect.qml b/src/quick/doc/snippets/qml/layerwitheffect.qml
new file mode 100644
index 0000000000..8cfac0bb19
--- /dev/null
+++ b/src/quick/doc/snippets/qml/layerwitheffect.qml
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Gunnar Sletta <gunnar@sletta.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.2
+
+Rectangle {
+ id: root
+ width: 320
+ height: 320
+
+ gradient: Gradient {
+ GradientStop { position: 0; color: "steelblue" }
+ GradientStop { position: 1; color: "black" }
+ }
+
+ property real cx: width / 2;
+ property real cy: height / 2;
+ property real boxSize: root.width * 0.2;
+ property real radius: width / 4;
+
+
+//! [1]
+Item {
+ id: layerRoot
+ layer.enabled: true
+ layer.effect: ShaderEffect {
+ fragmentShader: "
+ uniform lowp sampler2D source; // this item
+ uniform lowp float qt_Opacity; // inherited opacity of this item
+ varying highp vec2 qt_TexCoord0;
+ void main() {
+ lowp vec4 p = texture2D(source, qt_TexCoord0);
+ lowp float g = dot(p.xyz, vec3(0.344, 0.5, 0.156));
+ gl_FragColor = vec4(g, g, g, p.a) * qt_Opacity;
+ }"
+ }
+//! [1]
+
+ anchors.fill: parent
+
+
+ Repeater {
+ id: repeater
+ model: 200
+
+ Rectangle {
+ id: box
+
+ property real t: index / (repeater.model - 1);
+
+ width: 0
+ height: 0
+ x: root.cx - Math.sin(Math.PI * 2 * t) * root.radius;
+ y: root.cy - Math.cos(Math.PI * 2 * t) * root.radius;
+
+ Rectangle {
+ width: root.boxSize
+ height: root.boxSize
+ anchors.centerIn: parent
+ color: Qt.hsla(box.t, 0.5, 0.5);
+ border.color: "white"
+ antialiasing: true;
+ rotation: box.t * 360;
+// RotationAnimator on rotation {
+// from: box.t * 360;
+// to: box.t * 360 + 360;
+// duration: 7592;
+// loops: Animation.Infinite
+// }
+ }
+ }
+ }
+ }
+}
diff --git a/src/quick/doc/snippets/qml/opacitymask.qml b/src/quick/doc/snippets/qml/opacitymask.qml
new file mode 100644
index 0000000000..e458f810ea
--- /dev/null
+++ b/src/quick/doc/snippets/qml/opacitymask.qml
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Gunnar Sletta <gunnar@sletta.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Item {
+ id: root
+ width: 480
+ height: 320
+
+ // The checkers background
+ ShaderEffect {
+ id: tileBackground
+ anchors.fill: parent
+
+ property real tileSize: 20
+ property color color1: Qt.hsla(0, 0, 0.1);
+ property color color2: Qt.hsla(0, 0, 0.2);
+
+ property size pixelSize: Qt.size(width / tileSize, height / tileSize);
+
+ fragmentShader:
+ "
+ uniform lowp vec4 color1;
+ uniform lowp vec4 color2;
+ uniform highp vec2 pixelSize;
+ varying highp vec2 qt_TexCoord0;
+ void main() {
+ highp vec2 tc = sign(sin(3.14152 * qt_TexCoord0 * pixelSize));
+ if (tc.x != tc.y)
+ gl_FragColor = color1;
+ else
+ gl_FragColor = color2;
+ }
+ "
+ }
+
+//! [1]
+ Rectangle {
+ id: gradientRect;
+ width: 10
+ height: 10
+ gradient: Gradient {
+ GradientStop { position: 0; color: "white" }
+ GradientStop { position: 1; color: "steelblue" }
+ }
+ visible: false; // should not be visible on screen.
+ layer.enabled: true;
+ layer.smooth: true
+ }
+
+ Text {
+ id: textItem
+ font.pixelSize: 48
+ text: "Gradient Text"
+ anchors.centerIn: parent
+ layer.enabled: true
+ // This item should be used as the 'mask'
+ layer.samplerName: "maskSource"
+ layer.effect: ShaderEffect {
+ property var colorSource: gradientRect;
+ fragmentShader: "
+ uniform lowp sampler2D colorSource;
+ uniform lowp sampler2D maskSource;
+ uniform lowp float qt_Opacity;
+ varying highp vec2 qt_TexCoord0;
+ void main() {
+ gl_FragColor =
+ texture2D(colorSource, qt_TexCoord0)
+ * texture2D(maskSource, qt_TexCoord0).a
+ * qt_Opacity;
+ }
+ "
+ }
+ }
+//! [1]
+}
diff --git a/src/quick/doc/src/concepts/input/focus.qdoc b/src/quick/doc/src/concepts/input/focus.qdoc
index 065651c826..748c8eb53c 100644
--- a/src/quick/doc/src/concepts/input/focus.qdoc
+++ b/src/quick/doc/src/concepts/input/focus.qdoc
@@ -172,7 +172,7 @@ See \l{Qt Quick Examples - Key Interaction} for a
demonstration of moving keyboard focus between multiple areas using FocusScope
types.
-\section1 Advanced uses of Focus Scopes
+\section1 Advanced Uses of Focus Scopes
Focus scopes allow focus to allocation to be easily partitioned. Several
QML items use it to this effect.
diff --git a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc
index 49e4998ee1..dcc7a592e6 100644
--- a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc
+++ b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc
@@ -146,14 +146,14 @@ within the Qt install directory.
QAbstractItemModel presents a hierarchy of tables, but the views currently provided by QML
can only display list data.
In order to display the child lists of a hierarchical model,
-use the VisualDataModel type, which provides the following properties and functions to be used
+use the DelegateModel QML type, which provides the following properties and functions to be used
with list models of QAbstractItemModel type:
\list
\li \e hasModelChildren role property to determine whether a node has child nodes.
-\li \l VisualDataModel::rootIndex allows the root node to be specified
-\li \l VisualDataModel::modelIndex() returns a QModelIndex which can be assigned to VisualDataModel::rootIndex
-\li \l VisualDataModel::parentModelIndex() returns a QModelIndex which can be assigned to VisualDataModel::rootIndex
+\li \l DelegateModel::rootIndex allows the root node to be specified
+\li \l DelegateModel::modelIndex() returns a QModelIndex which can be assigned to DelegateModel::rootIndex
+\li \l DelegateModel::parentModelIndex() returns a QModelIndex which can be assigned to DelegateModel::rootIndex
\endlist
\section2 Exposing C++ Data Models to QML
diff --git a/src/quick/doc/src/concepts/positioning/righttoleft.qdoc b/src/quick/doc/src/concepts/positioning/righttoleft.qdoc
index 8f55cc8dd7..d6b1753ee3 100644
--- a/src/quick/doc/src/concepts/positioning/righttoleft.qdoc
+++ b/src/quick/doc/src/concepts/positioning/righttoleft.qdoc
@@ -69,7 +69,7 @@ the effective alignment of the text element that takes the mirroring into accoun
\snippet qml/righttoleft.qml 0
-\section1 Layout direction of positioners and views
+\section1 Layout Direction of Positioners and Views
(This applies to the \l Row, \l Grid, \l Flow, \l ListView and \l GridView types.)
@@ -85,7 +85,7 @@ views that takes the mirroring into account can be read from the \c effectiveLay
\snippet qml/righttoleft.qml 1
-\section1 Layout mirroring
+\section1 Layout Mirroring
The attached property \l LayoutMirroring is provided as a convenience for easily implementing right-to-left
support for existing left-to-right Qt Quick applications. It mirrors the behavior of \l {anchor-layout}
@@ -127,7 +127,7 @@ the animations and transitions continue to work as expected. If you do not have
right-to-left support for your application, it may be better to just keep the application layouts left
aligned and just make sure that text is translated and aligned properly.
-\section1 Mirroring icons
+\section1 Mirroring Icons
(This applies to \l Image, \l BorderImage and \l AnimatedImage types.)
@@ -136,7 +136,7 @@ The painting of these icons can be mirrored with a dedicated \c mirror property
\snippet qml/righttoleft.qml 5
-\section1 Default layout direction
+\section1 Default Layout Direction
The \l {QtQml::Qt::application}{Qt.application.layoutDirection} property can be used to query the active layout direction of the
application. It is based on QGuiApplication::layoutDirection(), which most commonly determines the layout
diff --git a/src/quick/doc/src/dynamicview-tutorial.qdoc b/src/quick/doc/src/dynamicview-tutorial.qdoc
index cf1115cf4a..619f0abd4b 100644
--- a/src/quick/doc/src/dynamicview-tutorial.qdoc
+++ b/src/quick/doc/src/dynamicview-tutorial.qdoc
@@ -136,7 +136,7 @@ so that is above other items in the stacking order and isn't obscured as it is d
The next step in our application to move items within the list as they're dragged so that we
can re-order the list. To achieve this we introduce three new types to our application;
-VisualDataModel, \l Drag and DropArea.
+DelegateModel, \l Drag and DropArea.
\snippet tutorials/dynamicview/dynamicview3/dynamicview.qml 0
\snippet tutorials/dynamicview/dynamicview3/dynamicview.qml 1
@@ -162,17 +162,17 @@ to the index of the item it was dragged over.
\snippet tutorials/dynamicview/dynamicview3/dynamicview.qml 3
-To move the items within the view we use a VisualDataModel. The VisualDataModel type is used by
+To move the items within the view we use a DelegateModel. The DelegateModel type is used by
the view types to instantiate delegate items from model data and when constructed explicitly can
be used to filter and re-order the model items provided to ListView. The
-\l {QtQuick::VisualDataModel::items}{items} property of VisualDataModel provides access to the
+\l {QtQuick::DelegateModel::items}{items} property of DelegateModel provides access to the
view's items and allows us to change the visible order without modifying the source model. To
-determine the current visible index of the items we use \l {QtQuick::VisualDataModel::itemsIndex}
-{itemsIndex} property on the VisualDataModel attached property of the delegate item.
+determine the current visible index of the items we use \l {QtQuick::DelegateModel::itemsIndex}
+{itemsIndex} property on the DelegateModel attached property of the delegate item.
-To utilize a VisualDataModel with a ListView we bind it to the \l {QtQuick::ListView::model}{model}
-property of the view and bind the \l {QtQuick::VisualDataModel::model}{model} and
-\l {QtQuick::VisualDataModel::delegate}{delegate} to the VisualDataModel.
+To utilize a DelegateModel with a ListView we bind it to the \l {QtQuick::ListView::model}{model}
+property of the view and bind the \l {QtQuick::DelegateModel::model}{model} and
+\l {QtQuick::DelegateModel::delegate}{delegate} to the DelegateModel.
\snippet tutorials/dynamicview/dynamicview3/dynamicview.qml 4
@@ -185,16 +185,16 @@ property of the view and bind the \l {QtQuick::VisualDataModel::model}{model} an
\example tutorials/dynamicview/dynamicview4
-Drag and drop isn't the only way items in a view can be re-ordered, using a VisualDataModel it is
-also possible to sort items based on model data. To do that we extend our VisualDataModel instance
+Drag and drop isn't the only way items in a view can be re-ordered, using a DelegateModel it is
+also possible to sort items based on model data. To do that we extend our DelegateModel instance
like this:
\snippet tutorials/dynamicview/dynamicview4/dynamicview.qml 0
\section2 Walkthrough
-Items in a VisualDataModel are filtered into groups represented by the VisualDataGroup type,
-normally all items in the model belong to a default \l {QtQuick::VisualDataModel::items}{items}
+Items in a DelegateModel are filtered into groups represented by the DelegateModelGroup type,
+normally all items in the model belong to a default \l {QtQuick::DelegateModel::items}{items}
group but this default can be changed with the includeByDefault property. To implement our sorting
we want items to first be added to an unsorted group from where we can transfer them to a sorted
position in the items group. To do that we clear includeByDefault on the items group and set it on
@@ -208,7 +208,7 @@ item and then transfer the item to the items group before moving it to the pre-d
repeat until the unsorted group is empty.
To find the insert position for an item we request a handle for the item from the unsorted group
-with the \l {QtQuick::VisualDataModel::get} {get} function. Through the model property on this
+with the \l {QtQuick::DelegateModel::get} {get} function. Through the model property on this
handle we can access the same model data that is available in a delegate instance of that item and
compare against other items to determine relative position.
@@ -219,8 +219,8 @@ of the list. In this example it can be one of the following:
\snippet tutorials/dynamicview/dynamicview4/dynamicview.qml 4
-A sort is triggered whenever new items are added to the unsorted VisualDataGroup which we are
-notified of by the \l {QtQuick::VisualDataGroup::onChanged}{onChanged} handler. If no sort
+A sort is triggered whenever new items are added to the unsorted DelegateModel which we are
+notified of by the \l {QtQuick::DelegateModelGroup::onChanged}{onChanged} handler. If no sort
function is currently selected we simply transfer all items from the unsorted group to the items
group, otherwise we call sort with the selected sort function.
@@ -228,8 +228,8 @@ group, otherwise we call sort with the selected sort function.
Finally when the selected sort order changes we can trigger a full re-sort of the list by moving
all items from the items group to the unsorted group, which will trigger the
-\l {QtQuick::VisualDataGroup::onChanged}{onChanged} handler and transfer the items back to the
-items group in correct order. Note that the \l {QtQuick::VisualDataGroup::onChanged}{onChanged}
+\l {QtQuick::DelegateModelGroup::onChanged}{onChanged} handler and transfer the items back to the
+items group in correct order. Note that the \l {QtQuick::DelegateModelGroup::onChanged}{onChanged}
handler will not be invoked recursively so there's no issue with it being invoked during a sort.
\snippet tutorials/dynamicview/dynamicview4/dynamicview.qml 6
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index 8249e268e8..15eb28350e 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -275,7 +275,7 @@ QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate()
\l{http://en.wikipedia.org/wiki/Screen_tearing}{screen tearing}) which will further
impact pixel operations with \c Canvas.FrambufferObject render target.
- \section1 Tips for Porting Existing HTML5 Canvas applications
+ \section1 Tips for Porting Existing HTML5 Canvas Applications
Although the Canvas item is provides a HTML5 like API, HTML5 canvas
applications need to be modified to run in the Canvas item:
@@ -667,7 +667,10 @@ void QQuickCanvasItem::itemChange(QQuickItem::ItemChange change, const QQuickIte
return;
d->window = value.window;
- if (d->window->isSceneGraphInitialized())
+ QSGRenderContext *context = QQuickWindowPrivate::get(d->window)->context;
+
+ // Rendering to FramebufferObject needs a valid OpenGL context.
+ if (context != 0 && (d->renderTarget != FramebufferObject || context->isValid()))
sceneGraphInitialized();
else
connect(d->window, SIGNAL(sceneGraphInitialized()), SLOT(sceneGraphInitialized()));
@@ -746,7 +749,7 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
QQuickContext2D *ctx = qobject_cast<QQuickContext2D *>(d->context);
QQuickContext2DTexture *factory = ctx->texture();
- QSGTexture *texture = factory->textureForNextFrame(node->texture());
+ QSGTexture *texture = factory->textureForNextFrame(node->texture(), window());
if (!texture) {
delete node;
d->node = 0;
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index 28c84facb5..d9ac3abdc3 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -3548,7 +3548,7 @@ void QQuickContext2D::clip()
state.clip = true;
state.clipPath = clipPath;
}
- buffer()->clip(state.clipPath);
+ buffer()->clip(state.clip, state.clipPath);
}
void QQuickContext2D::stroke()
@@ -4283,8 +4283,8 @@ void QQuickContext2D::popState()
if (newState.miterLimit != state.miterLimit)
buffer()->setMiterLimit(newState.miterLimit);
- if (newState.clip && (!state.clip || newState.clipPath != state.clipPath))
- buffer()->clip(newState.clipPath);
+ if (newState.clip != state.clip || newState.clipPath != state.clipPath)
+ buffer()->clip(newState.clip, newState.clipPath);
if (newState.shadowBlur != state.shadowBlur)
buffer()->setShadowBlur(newState.shadowBlur);
diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
index 3fb230b928..eac5e2cef8 100644
--- a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
+++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
@@ -207,6 +207,7 @@ void QQuickContext2DCommandBuffer::setPainterState(QPainter* p, const QQuickCont
if (state.globalCompositeOperation != p->compositionMode())
p->setCompositionMode(state.globalCompositeOperation);
+ p->setClipping(state.clip);
if (state.clip)
p->setClipPath(state.clipPath);
}
@@ -383,9 +384,11 @@ void QQuickContext2DCommandBuffer::replay(QPainter* p, QQuickContext2D::State& s
}
case QQuickContext2D::Clip:
{
+ state.clip = takeBool();
state.clipPath = takePath();
- p->setClipping(true);
- p->setClipPath(state.clipPath);
+ p->setClipping(state.clip);
+ if (state.clip)
+ p->setClipPath(state.clipPath);
break;
}
case QQuickContext2D::GlobalAlpha:
diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h b/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
index 9b2fde33d8..4e6232ac7f 100644
--- a/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
+++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
@@ -145,9 +145,10 @@ public:
pathes << path;
}
- inline void clip(const QPainterPath& path)
+ inline void clip(bool enabled, const QPainterPath& path)
{
commands << QQuickContext2D::Clip;
+ bools << enabled;
pathes << path;
}
diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp
index a3b316a217..1dd8e50387 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture.cpp
+++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp
@@ -427,7 +427,7 @@ QVector2D QQuickContext2DFBOTexture::scaleFactor() const
m_fbo->height() / m_fboSize.height());
}
-QSGTexture *QQuickContext2DFBOTexture::textureForNextFrame(QSGTexture *lastTexture)
+QSGTexture *QQuickContext2DFBOTexture::textureForNextFrame(QSGTexture *lastTexture, QQuickWindow *)
{
QSGPlainTexture *texture = static_cast<QSGPlainTexture *>(lastTexture);
@@ -666,22 +666,15 @@ void QQuickContext2DImageTexture::grabImage(const QRectF& rf)
QQuickContext2D::mutex.unlock();
}
-QSGTexture *QQuickContext2DImageTexture::textureForNextFrame(QSGTexture *last)
+QSGTexture *QQuickContext2DImageTexture::textureForNextFrame(QSGTexture *last, QQuickWindow *window)
{
- QSGPlainTexture *texture = static_cast<QSGPlainTexture *>(last);
-
if (m_onCustomThread)
m_mutex.lock();
- if (!texture) {
- texture = new QSGPlainTexture();
- texture->setHasAlphaChannel(true);
- m_dirtyTexture = true;
- }
- if (m_dirtyTexture) {
- texture->setImage(m_displayImage);
- m_dirtyTexture = false;
- }
+ delete last;
+
+ QSGTexture *texture = window->createTextureFromImage(m_displayImage, QQuickWindow::TextureCanUseAtlas);
+ m_dirtyTexture = false;
if (m_onCustomThread)
m_mutex.unlock();
diff --git a/src/quick/items/context2d/qquickcontext2dtexture_p.h b/src/quick/items/context2d/qquickcontext2dtexture_p.h
index 10ac246d1b..3ff0cb12c1 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture_p.h
+++ b/src/quick/items/context2d/qquickcontext2dtexture_p.h
@@ -102,7 +102,7 @@ public:
bool isOnCustomThread() const { return m_onCustomThread; }
// Called during sync() on the scene graph thread while GUI is blocked.
- virtual QSGTexture *textureForNextFrame(QSGTexture *lastFrame) = 0;
+ virtual QSGTexture *textureForNextFrame(QSGTexture *lastFrame, QQuickWindow *window) = 0;
bool event(QEvent *e);
void initializeOpenGL(QOpenGLContext *gl, QOffscreenSurface *s) {
@@ -173,7 +173,7 @@ public:
virtual void compositeTile(QQuickContext2DTile* tile);
QSize adjustedTileSize(const QSize &ts);
- QSGTexture *textureForNextFrame(QSGTexture *);
+ QSGTexture *textureForNextFrame(QSGTexture *, QQuickWindow *window);
protected:
QVector2D scaleFactor() const Q_DECL_OVERRIDE;
@@ -209,7 +209,7 @@ public:
virtual void endPainting();
virtual void compositeTile(QQuickContext2DTile* tile);
- virtual QSGTexture *textureForNextFrame(QSGTexture *lastFrame);
+ virtual QSGTexture *textureForNextFrame(QSGTexture *lastFrame, QQuickWindow *window);
public Q_SLOTS:
virtual void grabImage(const QRectF& region = QRectF());
diff --git a/src/quick/items/qquickborderimage.cpp b/src/quick/items/qquickborderimage.cpp
index 50a0a76267..8d8e4b6a02 100644
--- a/src/quick/items/qquickborderimage.cpp
+++ b/src/quick/items/qquickborderimage.cpp
@@ -562,7 +562,9 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
// Don't implicitly create the scalegrid in the rendering thread...
QRectF innerSourceRect(0, 0, 1, 1);
QRectF innerTargetRect(0, 0, width(), height());
- int borderLeft, borderTop, borderRight, borderBottom;
+ int borderLeft = 0, borderTop = 0, borderRight = 0, borderBottom = 0;
+
+ bool updateNode = !oldNode;
if (d->border) {
const QQuickScaleGrid *border = d->getScaleGrid();
@@ -579,11 +581,17 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
borderTop,
qMax<qreal>(0, width() - border->right() - border->left()),
qMax<qreal>(0, height() - border->bottom() - border->top()));
+
+ if (innerSourceRect != d->oldInnerSourceRect || innerTargetRect != d->oldInnerTargetRect)
+ updateNode = true;
+ d->oldInnerSourceRect = innerSourceRect;
+ d->oldInnerTargetRect = innerTargetRect;
}
bool updatePixmap = d->pixmapChanged;
d->pixmapChanged = false;
- if (!oldNode) {
+ if (updateNode) {
+ delete oldNode;
oldNode = new QSGNode;
updatePixmap = true;
@@ -591,33 +599,130 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
d->regions[i].node = 0;
if (innerSourceRect.left() > 0) {
- if (innerSourceRect.top() > 0)
- d->regions[0].node = d->sceneGraphContext()->createImageNode();
- if (innerSourceRect.bottom() < 1)
- d->regions[6].node = d->sceneGraphContext()->createImageNode();
+ if (innerSourceRect.top() > 0) {
+ QRectF rect(0,
+ 0,
+ innerTargetRect.left(),
+ innerTargetRect.top());
+
+ if (!rect.isEmpty()) {
+ d->regions[0].node = d->sceneGraphContext()->createImageNode();
+ d->regions[0].node->setTargetRect(rect);
+ d->regions[0].node->setInnerTargetRect(rect);
+ d->regions[0].targetRect = rect;
+ }
+ }
+
+ if (innerSourceRect.bottom() < 1) {
+ QRectF rect(0,
+ innerTargetRect.bottom(),
+ innerTargetRect.left(),
+ height() - innerTargetRect.height() - innerTargetRect.top());
+
+ if (!rect.isEmpty()) {
+ d->regions[6].node = d->sceneGraphContext()->createImageNode();
+ d->regions[6].node->setTargetRect(rect);
+ d->regions[6].node->setInnerTargetRect(rect);
+ d->regions[6].targetRect = rect;
+ }
+ }
- if (innerSourceRect.top() < innerSourceRect.bottom())
- d->regions[3].node = d->sceneGraphContext()->createImageNode();
+ if (innerSourceRect.top() < innerSourceRect.bottom()) {
+ QRectF rect(0,
+ innerTargetRect.top(),
+ innerTargetRect.left(),
+ innerTargetRect.height());
+
+ if (!rect.isEmpty()) {
+ d->regions[3].node = d->sceneGraphContext()->createImageNode();
+ d->regions[3].node->setTargetRect(rect);
+ d->regions[3].node->setInnerTargetRect(rect);
+ d->regions[3].targetRect = rect;
+ }
+ }
}
if (innerSourceRect.right() < 1) {
- if (innerSourceRect.top() > 0)
- d->regions[2].node = d->sceneGraphContext()->createImageNode();
- if (innerSourceRect.bottom() < 1)
- d->regions[8].node = d->sceneGraphContext()->createImageNode();
+ if (innerSourceRect.top() > 0) {
+ QRectF rect(innerTargetRect.right(),
+ 0,
+ width() - innerTargetRect.width() - innerTargetRect.left(),
+ innerTargetRect.top());
+
+ if (!rect.isEmpty()) {
+ d->regions[2].node = d->sceneGraphContext()->createImageNode();
+ d->regions[2].node->setTargetRect(rect);
+ d->regions[2].node->setInnerTargetRect(rect);
+ d->regions[2].targetRect = rect;
+ }
+ }
- if (innerSourceRect.top() < innerSourceRect.bottom())
- d->regions[5].node = d->sceneGraphContext()->createImageNode();
+ if (innerSourceRect.bottom() < 1) {
+ QRectF rect(innerTargetRect.right(),
+ innerTargetRect.bottom(),
+ width() - innerTargetRect.width() - innerTargetRect.left(),
+ height() - innerTargetRect.height() - innerTargetRect.top());
+
+ if (!rect.isEmpty()) {
+ d->regions[8].node = d->sceneGraphContext()->createImageNode();
+ d->regions[8].node->setTargetRect(rect);
+ d->regions[8].node->setInnerTargetRect(rect);
+ d->regions[8].targetRect = rect;
+ }
+ }
+
+ if (innerSourceRect.top() < innerSourceRect.bottom()) {
+ QRectF rect(innerTargetRect.right(),
+ innerTargetRect.top(),
+ width() - innerTargetRect.width() - innerTargetRect.left(),
+ innerTargetRect.height());
+
+ if (!rect.isEmpty()) {
+ d->regions[5].node = d->sceneGraphContext()->createImageNode();
+ d->regions[5].node->setTargetRect(rect);
+ d->regions[5].node->setInnerTargetRect(rect);
+ d->regions[5].targetRect = rect;
+ }
+ }
}
- if (innerSourceRect.top() > 0 && innerSourceRect.left() < innerSourceRect.right())
- d->regions[1].node = d->sceneGraphContext()->createImageNode();
+ if (innerSourceRect.top() > 0 && innerSourceRect.left() < innerSourceRect.right()) {
+ QRectF rect(innerTargetRect.left(),
+ 0,
+ innerTargetRect.width(),
+ innerTargetRect.top());
+
+ if (!rect.isEmpty()) {
+ d->regions[1].node = d->sceneGraphContext()->createImageNode();
+ d->regions[1].node->setTargetRect(rect);
+ d->regions[1].node->setInnerTargetRect(rect);
+ d->regions[1].targetRect = rect;
+ }
+ }
- if (innerSourceRect.bottom() < 1 && innerSourceRect.left() < innerSourceRect.right())
- d->regions[7].node = d->sceneGraphContext()->createImageNode();
+ if (innerSourceRect.bottom() < 1 && innerSourceRect.left() < innerSourceRect.right()) {
+ QRectF rect(innerTargetRect.left(),
+ innerTargetRect.bottom(),
+ innerTargetRect.width(),
+ height() - innerTargetRect.height() - innerTargetRect.top());
+
+ if (!rect.isEmpty()) {
+ d->regions[7].node = d->sceneGraphContext()->createImageNode();
+ d->regions[7].node->setTargetRect(rect);
+ d->regions[7].node->setInnerTargetRect(rect);
+ d->regions[7].targetRect = rect;
+ }
+ }
- if (innerSourceRect.left() < innerSourceRect.right() && innerSourceRect.top() < innerSourceRect.bottom())
- d->regions[4].node = d->sceneGraphContext()->createImageNode();
+ if (innerSourceRect.left() < innerSourceRect.right()
+ && innerSourceRect.top() < innerSourceRect.bottom()) {
+ if (!innerTargetRect.isEmpty()) {
+ d->regions[4].node = d->sceneGraphContext()->createImageNode();
+ d->regions[4].node->setInnerTargetRect(innerTargetRect);
+ d->regions[4].node->setTargetRect(innerTargetRect);
+ d->regions[4].targetRect = innerTargetRect;
+ }
+ }
for (int i=0; i<9; ++i) {
if (d->regions[i].node != 0)
@@ -638,14 +743,6 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (d->regions[3].node == 0 && d->regions[6].node == 0)
antialiasing |= QSGImageNode::AntialiasingBottom;
d->regions[0].node->setAntialiasing(antialiasing);
-
- QRectF rect(0,
- 0,
- innerTargetRect.left(),
- innerTargetRect.top());
- d->regions[0].node->setTargetRect(rect);
- d->regions[0].node->setInnerTargetRect(rect);
- d->regions[0].targetRect = rect;
}
if (d->regions[1].node != 0) {
@@ -660,14 +757,6 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (d->regions[4].node == 0 && d->regions[7].node == 0)
antialiasing |= QSGImageNode::AntialiasingBottom;
d->regions[1].node->setAntialiasing(antialiasing);
-
- QRectF rect(innerTargetRect.left(),
- 0,
- innerTargetRect.width(),
- innerTargetRect.top());
- d->regions[1].node->setTargetRect(rect);
- d->regions[1].node->setInnerTargetRect(rect);
- d->regions[1].targetRect = rect;
}
if (d->regions[2].node != 0) {
@@ -680,14 +769,6 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (d->regions[5].node == 0 && d->regions[8].node == 0)
antialiasing |= QSGImageNode::AntialiasingBottom;
d->regions[2].node->setAntialiasing(antialiasing);
-
- QRectF rect(innerTargetRect.right(),
- 0,
- width() - innerTargetRect.width() - innerTargetRect.left(),
- innerTargetRect.top());
- d->regions[2].node->setTargetRect(rect);
- d->regions[2].node->setInnerTargetRect(rect);
- d->regions[2].targetRect = rect;
}
if (d->regions[3].node != 0) {
@@ -702,14 +783,6 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (d->regions[0].node == 0)
antialiasing |= QSGImageNode::AntialiasingTop;
d->regions[3].node->setAntialiasing(antialiasing);
-
- QRectF rect(0,
- innerTargetRect.top(),
- innerTargetRect.left(),
- innerTargetRect.height());
- d->regions[3].node->setTargetRect(rect);
- d->regions[3].node->setInnerTargetRect(rect);
- d->regions[3].targetRect = rect;
}
if (d->regions[4].node != 0) {
@@ -731,10 +804,6 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (d->regions[7].node == 0)
antialiasing |= QSGImageNode::AntialiasingBottom;
d->regions[4].node->setAntialiasing(antialiasing);
-
- d->regions[4].node->setInnerTargetRect(innerTargetRect);
- d->regions[4].node->setTargetRect(innerTargetRect);
- d->regions[4].targetRect = innerTargetRect;
}
if (d->regions[5].node != 0) {
@@ -749,14 +818,6 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (d->regions[8].node == 0)
antialiasing |= QSGImageNode::AntialiasingBottom;
d->regions[5].node->setAntialiasing(antialiasing);
-
- QRectF rect(innerTargetRect.right(),
- innerTargetRect.top(),
- width() - innerTargetRect.width() - innerTargetRect.left(),
- innerTargetRect.height());
- d->regions[5].node->setTargetRect(rect);
- d->regions[5].node->setInnerTargetRect(rect);
- d->regions[5].targetRect = rect;
}
if (d->regions[6].node != 0) {
@@ -769,14 +830,6 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (d->regions[3].node == 0 && d->regions[0].node == 0)
antialiasing |= QSGImageNode::AntialiasingTop;
d->regions[6].node->setAntialiasing(antialiasing);
-
- QRectF rect(0,
- innerTargetRect.bottom(),
- innerTargetRect.left(),
- height() - innerTargetRect.height() - innerTargetRect.top());
- d->regions[6].node->setTargetRect(rect);
- d->regions[6].node->setInnerTargetRect(rect);
- d->regions[6].targetRect = rect;
}
if (d->regions[7].node != 0) {
@@ -791,14 +844,6 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (d->regions[4].node == 0 && d->regions[1].node == 0)
antialiasing |= QSGImageNode::AntialiasingTop;
d->regions[7].node->setAntialiasing(antialiasing);
-
- QRectF rect(innerTargetRect.left(),
- innerTargetRect.bottom(),
- innerTargetRect.width(),
- height() - innerTargetRect.height() - innerTargetRect.top());
- d->regions[7].node->setTargetRect(rect);
- d->regions[7].node->setInnerTargetRect(rect);
- d->regions[7].targetRect = rect;
}
if (d->regions[8].node != 0) {
@@ -811,14 +856,6 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (d->regions[5].node == 0 && d->regions[2].node == 0)
antialiasing |= QSGImageNode::AntialiasingTop;
d->regions[8].node->setAntialiasing(antialiasing);
-
- QRectF rect(innerTargetRect.right(),
- innerTargetRect.bottom(),
- width() - innerTargetRect.width() - innerTargetRect.left(),
- height() - innerTargetRect.height() - innerTargetRect.top());
- d->regions[8].node->setTargetRect(rect);
- d->regions[8].node->setInnerTargetRect(rect);
- d->regions[8].targetRect = rect;
}
for (int i=0; i<9; ++i) {
diff --git a/src/quick/items/qquickdrag.cpp b/src/quick/items/qquickdrag.cpp
index c85b1416f6..e49347351c 100644
--- a/src/quick/items/qquickdrag.cpp
+++ b/src/quick/items/qquickdrag.cpp
@@ -112,23 +112,23 @@ public:
\ingroup qtquick-input
\brief For specifying drag and drop events for moved Items
- Using the Drag attached property any Item can be made a source of drag and drop
+ Using the Drag attached property, any Item can be made a source of drag and drop
events within a scene.
- When a drag is \l active on an item any change in that item's position will
+ When a drag is \l active on an item, any change in that item's position will
generate a drag event that will be sent to any DropArea that intersects
with the new position of the item. Other items which implement drag and
drop event handlers can also receive these events.
The following snippet shows how an item can be dragged with a MouseArea.
- However, dragging is not limited to mouse drags, anything that can move an item
- can generate drag events, this can include touch events, animations and bindings.
+ However, dragging is not limited to mouse drags; anything that can move an item
+ can generate drag events, including touch events, animations and bindings.
\snippet qml/drag.qml 0
A drag can be terminated either by canceling it with Drag.cancel() or setting
Drag.active to false, or it can be terminated with a drop event by calling
- Drag.drop(). If the drop event is accepted Drag.drop() will return the
+ Drag.drop(). If the drop event is accepted, Drag.drop() will return the
\l {supportedActions}{drop action} chosen by the recipient of the event,
otherwise it will return Qt.IgnoreAction.
@@ -314,7 +314,8 @@ void QQuickDragAttached::setActive(bool active)
\qmlattachedproperty Object QtQuick::Drag::source
This property holds an object that is identified to recipients of drag events as
- the source of the events. By default this is the item Drag property is attached to.
+ the source of the events. By default this is the item that the Drag
+ property is attached to.
Changing the source while a drag is active will reset the sequence of drag events by
sending a drag leave event followed by a drag enter event with the new source.
diff --git a/src/quick/items/qquickframebufferobject.cpp b/src/quick/items/qquickframebufferobject.cpp
index da1709f055..dc4668be3f 100644
--- a/src/quick/items/qquickframebufferobject.cpp
+++ b/src/quick/items/qquickframebufferobject.cpp
@@ -254,6 +254,7 @@ QSGNode *QQuickFramebufferObject::updatePaintNode(QSGNode *node, UpdatePaintNode
n->fbo = 0;
delete n->msDisplayFbo;
n->msDisplayFbo = 0;
+ n->invalidatePending = false;
}
}
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp
index db8cc0532e..e3af926e22 100644
--- a/src/quick/items/qquickgridview.cpp
+++ b/src/quick/items/qquickgridview.cpp
@@ -1173,7 +1173,7 @@ bool QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
fully outside the view.
- \section1 GridView layouts
+ \section1 GridView Layouts
The layout of the items in a GridView can be controlled by these properties:
diff --git a/src/quick/items/qquickimagebase_p_p.h b/src/quick/items/qquickimagebase_p_p.h
index f30eacb4ac..ec2f0bb73e 100644
--- a/src/quick/items/qquickimagebase_p_p.h
+++ b/src/quick/items/qquickimagebase_p_p.h
@@ -75,6 +75,8 @@ public:
QSize sourcesize;
QSize oldSourceSize;
qreal devicePixelRatio;
+ QRectF oldInnerSourceRect;
+ QRectF oldInnerTargetRect;
bool async : 1;
bool cache : 1;
bool mirror: 1;
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index d45fb31fd9..b8362c9dac 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -397,7 +397,7 @@ void QQuickItemKeyFilter::componentComplete()
\c KeyNavigation.BeforeItem allows the event to be used for key navigation
before the item, rather than after.
- If item to which the focus is switching is not enabled or visible, an attempt will
+ If the item to which the focus is switching is not enabled or visible, an attempt will
be made to skip this item and focus on the next. This is possible if there are
a chain of items with the same KeyNavigation handler. If multiple items in a row are not enabled
or visible, they will also be skipped.
@@ -405,7 +405,7 @@ void QQuickItemKeyFilter::componentComplete()
KeyNavigation will implicitly set the other direction to return focus to this item. So if you set
\l left to another item, \l right will be set on that item's KeyNavigation to set focus back to this
item. However, if that item's KeyNavigation has had right explicitly set then no change will occur.
- This means that the above example could have been written, with the same behaviour, without specifying
+ This means that the example above could achieve the same behavior without specifying
KeyNavigation.right or KeyNavigation.down for any of the items.
\sa {Keys}{Keys attached property}
@@ -887,6 +887,8 @@ bool QQuickKeysAttached::isConnected(const char *signalName)
handling. If the item accepts the key event it will not be
handled by the Keys attached property handler.
\endlist
+
+ \sa {Key Handling Priorities}
*/
/*!
@@ -914,6 +916,9 @@ bool QQuickKeysAttached::isConnected(const char *signalName)
focus: true
}
\endqml
+
+ To see the order in which events are received when using forwardTo, see
+ \l {Key Handling Priorities}.
*/
/*!
@@ -1833,6 +1838,101 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus)
their layouts.
See LayoutMirroring for more details.
+
+ \section1 Item Layers
+
+ An Item will normally be rendered directly into the window it
+ belongs to. However, by setting \l layer.enabled, it is possible
+ to delegate the item and its entire subtree into an offscreen
+ surface. Only the offscreen surface, a texture, will be then drawn
+ into the window.
+
+ If it is desired to have a texture size different from that of the
+ item, this is possible using \l layer.textureSize. To render only
+ a section of the item into the texture, use \l
+ layer.sourceRect. It is also possible to specify \l
+ layer.sourceRect so it extends beyond the bounds of the item. In
+ this case, the exterior will be padded with transparent pixels.
+
+ The item will use linear interpolation for scaling if
+ \l layer.smooth is set to \c true and will use mipmap for
+ downsampling if \l layer.mipmap is set to \c true. Mipmapping may
+ improve visual quality of downscaled items. For mipmapping of
+ single Image items, prefer Image::mipmap.
+
+ \section2 Layer Opacity vs Item Opacity
+
+ When applying \l opacity to an item hierarchy the opacity is
+ applied to each item individually. This can lead to undesired
+ visual results when the opacity is applied to a subtree. Consider
+ the following example:
+
+ \table
+ \row
+ \li \inlineimage qml-blending-nonlayered.png
+ \li \b {Non-layered Opacity} \snippet qml/layerblending.qml non-layered
+ \endtable
+
+ A layer is rendered with the root item's opacity being 1, and then
+ the root item's opacity is applied to the texture when it is
+ drawn. This means that fading in a large item hierarchy from
+ transparent to opaque, or vice versa, can be done without the
+ overlap artifacts that the normal item by item alpha blending
+ has. Here is the same example with layer enabled:
+
+ \table
+ \row
+ \li \image qml-blending-layered.png
+ \li \b {Layered Opacity} \snippet qml/layerblending.qml layered
+ \endtable
+
+ \section2 Combined with ShaderEffects
+
+ Setting \l layer.enabled to true will turn the item into a \l
+ {QQuickItem::isTextureProvider}{texture provider}, making it
+ possible to use the item directly as a texture, for instance
+ in combination with the ShaderEffect type.
+
+ It is possible to apply an effect on a layer at runtime using
+ layer.effect:
+
+ \snippet qml/layerwitheffect.qml 1
+
+ In this example, we implement the shader effect manually. The \l
+ {Qt Graphical Effects} module contains a suite of ready-made
+ effects for use with Qt Quick.
+
+ See ShaderEffect for more information about using effects.
+
+ \note \l layer.enabled is actually just a more convenient way of using
+ ShaderEffectSource.
+
+
+ \section2 Memory and Performance
+
+ When an item's layer is enabled, the scene graph will allocate memory
+ in the GPU equal to \c {width x height x 4}. In memory constrained
+ configurations, large layers should be used with care.
+
+ In the QPainter / QWidget world, it is some times favorable to
+ cache complex content in a pixmap, image or texture. In Qt Quick,
+ because of the techniques already applied by the \l {Qt Quick
+ Scene Graph Renderer} {scene graph renderer}, this will in most
+ cases not be the case. Excessive draw calls are already reduced
+ because of batching and a cache will in most cases end up blending
+ more pixels than the original content. The overhead of rendering
+ to an offscreen and the blending involved with drawing the
+ resulting texture is therefore often more costly than simply
+ letting the item and its children be drawn normally.
+
+ Also, an item using a layer can not be \l {Batching} {batched} during
+ rendering. This means that a scene with many layered items may
+ have performance problems.
+
+ Layering can be convenient and useful for visual effects, but
+ should in most cases be enabled for the duration of the effect and
+ disabled afterwards.
+
*/
/*!
@@ -7481,12 +7581,15 @@ void QQuickItemLayer::setMipmap(bool mipmap)
allow you to save some texture memory.
\list
- \li ShaderEffectSource.Alpha - GL_ALPHA
+ \li ShaderEffectSource.Alpha - GL_ALPHA;
\li ShaderEffectSource.RGB - GL_RGB
\li ShaderEffectSource.RGBA - GL_RGBA
\endlist
- \note Some OpenGL implementations do not support the GL_ALPHA format.
+ \note ShaderEffectSource.RGB and ShaderEffectSource.Alpha should
+ be used with caution, as support for these formats in the underlying
+ hardare and driver is often not present.
+
*/
void QQuickItemLayer::setFormat(QQuickShaderEffectSource::Format f)
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 0037879fb3..851204ccde 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -1742,7 +1742,7 @@ bool QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
nicely.
- \section1 ListView layouts
+ \section1 ListView Layouts
The layout of the items in a ListView can be controlled by these properties:
diff --git a/src/quick/items/qquickscreen.cpp b/src/quick/items/qquickscreen.cpp
index 0d9226d77f..926ac7b4ee 100644
--- a/src/quick/items/qquickscreen.cpp
+++ b/src/quick/items/qquickscreen.cpp
@@ -171,6 +171,9 @@ QT_BEGIN_NAMESPACE
change, then probably you are using a device which does not rotate its own
display. In that case you may need to use \l {Item::rotation}{Item.rotation} or
\l {Item::transform}{Item.transform} to rotate your content.
+
+ \note This property does not update unless a Screen::orientationUpdateMask
+ is set to a value other than \c 0.
*/
/*!
\qmlattachedmethod int Screen::angleBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b)
@@ -178,10 +181,21 @@ QT_BEGIN_NAMESPACE
Returns the rotation angle, in degrees, between the two specified angles.
*/
+/*!
+ \qmlattachedproperty Qt::ScreenOrientations Screen::orientationUpdateMask
+ \since 5.4
+
+ This contains the update mask for the orientation. Screen::orientation
+ only emits changes for the screen orientations matching this mask.
+
+ The default, \c 0, means Screen::orientation never updates.
+*/
+
QQuickScreenAttached::QQuickScreenAttached(QObject* attachee)
: QObject(attachee)
, m_screen(NULL)
, m_window(NULL)
+ , m_updateMask(0)
{
m_attachee = qobject_cast<QQuickItem*>(attachee);
@@ -260,6 +274,24 @@ Qt::ScreenOrientation QQuickScreenAttached::orientation() const
return m_screen->orientation();
}
+Qt::ScreenOrientations QQuickScreenAttached::orientationUpdateMask() const
+{
+ return m_updateMask;
+}
+
+void QQuickScreenAttached::setOrientationUpdateMask(Qt::ScreenOrientations mask)
+{
+ if (m_updateMask == mask)
+ return;
+
+ m_updateMask = mask;
+
+ if (m_screen)
+ m_screen->setOrientationUpdateMask(m_updateMask);
+
+ emit orientationUpdateMaskChanged();
+}
+
int QQuickScreenAttached::angleBetween(int a, int b)
{
if (!m_screen)
@@ -290,6 +322,8 @@ void QQuickScreenAttached::screenChanged(QScreen *screen)
if (!screen)
return; //Don't bother emitting signals, because the new values are garbage anyways
+ screen->setOrientationUpdateMask(m_updateMask);
+
if (!oldScreen || screen->size() != oldScreen->size()) {
emit widthChanged();
emit heightChanged();
diff --git a/src/quick/items/qquickscreen_p.h b/src/quick/items/qquickscreen_p.h
index 884995a67e..d661cc6f56 100644
--- a/src/quick/items/qquickscreen_p.h
+++ b/src/quick/items/qquickscreen_p.h
@@ -50,15 +50,19 @@ class Q_AUTOTEST_EXPORT QQuickScreenAttached : public QObject
{
Q_OBJECT
- Q_PROPERTY(QString name READ name NOTIFY nameChanged);
+ Q_PROPERTY(QString name READ name NOTIFY nameChanged)
Q_PROPERTY(int width READ width NOTIFY widthChanged)
Q_PROPERTY(int height READ height NOTIFY heightChanged)
Q_PROPERTY(int desktopAvailableWidth READ desktopAvailableWidth NOTIFY desktopGeometryChanged)
Q_PROPERTY(int desktopAvailableHeight READ desktopAvailableHeight NOTIFY desktopGeometryChanged)
Q_PROPERTY(qreal logicalPixelDensity READ logicalPixelDensity NOTIFY logicalPixelDensityChanged)
Q_PROPERTY(qreal pixelDensity READ pixelDensity NOTIFY pixelDensityChanged)
+ // TODO Qt 6 Rename primaryOrientation to orientation
Q_PROPERTY(Qt::ScreenOrientation primaryOrientation READ primaryOrientation NOTIFY primaryOrientationChanged)
+ // TODO Qt 6 Remove this orientation -> incomplete device orientation -> better use OrientationSensor
Q_PROPERTY(Qt::ScreenOrientation orientation READ orientation NOTIFY orientationChanged)
+ Q_PROPERTY(Qt::ScreenOrientations orientationUpdateMask READ orientationUpdateMask
+ WRITE setOrientationUpdateMask NOTIFY orientationUpdateMaskChanged)
public:
QQuickScreenAttached(QObject* attachee);
@@ -72,6 +76,8 @@ public:
qreal pixelDensity() const;
Qt::ScreenOrientation primaryOrientation() const;
Qt::ScreenOrientation orientation() const;
+ Qt::ScreenOrientations orientationUpdateMask() const;
+ void setOrientationUpdateMask(Qt::ScreenOrientations mask);
//Treats int as Qt::ScreenOrientation, due to QTBUG-20639
Q_INVOKABLE int angleBetween(int a, int b);
@@ -87,6 +93,7 @@ Q_SIGNALS:
void pixelDensityChanged();
void primaryOrientationChanged();
void orientationChanged();
+ void orientationUpdateMaskChanged();
protected Q_SLOTS:
void screenChanged(QScreen*);
@@ -95,6 +102,7 @@ private:
QScreen* m_screen;
QQuickWindow* m_window;
QQuickItem* m_attachee;
+ Qt::ScreenOrientations m_updateMask;
};
class Q_AUTOTEST_EXPORT QQuickScreen : public QObject
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index fb5dac1080..0358495a3b 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -641,10 +641,34 @@ void QQuickShaderEffectCommon::propertyChanged(QQuickItem *item, int mappedId,
corner. For non-linear vertex transformations, like page curl, you can
specify a fine grid of vertices by specifying a \l mesh resolution.
+ \section1 ShaderEffect and Item Layers
+
+ The ShaderEffect type can be combined with \l {Item Layers} {layered items}.
+
+ \table
+ \row
+ \li \b {Layer with effect disabled} \inlineimage qml-shadereffect-nolayereffect.png
+ \li \b {Layer with effect enabled} \inlineimage qml-shadereffect-layereffect.png
+ \li \snippet qml/layerwitheffect.qml 1
+ \endtable
+
+ It is also possible to combine multiple layered items:
+
+ \table
+ \row
+ \li \inlineimage qml-shadereffect-opacitymask.png
+ \li \snippet qml/opacitymask.qml 1
+ \endtable
+
+ The \l {Qt Graphical Effects} module contains several ready-made effects
+ for using with Qt Quick applications.
+
\note Scene Graph textures have origin in the top-left corner rather than
bottom-left which is common in OpenGL.
For information about the GLSL version being used, see \l QtQuick::OpenGLInfo.
+
+ \sa {Item Layers}
*/
QQuickShaderEffect::QQuickShaderEffect(QQuickItem *parent)
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp
index 80be283443..52e5ba2464 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -74,7 +74,6 @@ public:
QSGTexture::WrapMode horizontalWrap;
QSGTexture::WrapMode verticalWrap;
};
-#include "qquickshadereffectsource.moc"
class QQuickShaderEffectSourceCleanup : public QRunnable
{
@@ -322,24 +321,28 @@ void QQuickShaderEffectSource::setSourceItem(QQuickItem *item)
d->derefWindow();
}
- if (window() == item->window()) {
- m_sourceItem = item;
- } else {
- qWarning("ShaderEffectSource: sourceItem and ShaderEffectSource must both be children of the same window.");
- m_sourceItem = 0;
- }
+ m_sourceItem = item;
if (m_sourceItem) {
- QQuickItemPrivate *d = QQuickItemPrivate::get(item);
- // 'item' needs a window to get a scene graph node. It usually gets one through its
- // parent, but if the source item is "inline" rather than a reference -- i.e.
- // "sourceItem: Item { }" instead of "sourceItem: foo" -- it will not get a parent.
- // In those cases, 'item' should get the window from 'this'.
- if (window())
- d->refWindow(window());
- d->refFromEffectItem(m_hideSource);
- d->addItemChangeListener(this, QQuickItemPrivate::Geometry);
- connect(m_sourceItem, SIGNAL(destroyed(QObject*)), this, SLOT(sourceItemDestroyed(QObject*)));
+ if (window() == m_sourceItem->window()
+ || (window() == 0 && m_sourceItem->window())
+ || (m_sourceItem->window() == 0 && window())) {
+ QQuickItemPrivate *d = QQuickItemPrivate::get(item);
+ // 'item' needs a window to get a scene graph node. It usually gets one through its
+ // parent, but if the source item is "inline" rather than a reference -- i.e.
+ // "sourceItem: Item { }" instead of "sourceItem: foo" -- it will not get a parent.
+ // In those cases, 'item' should get the window from 'this'.
+ if (window())
+ d->refWindow(window());
+ else if (m_sourceItem->window())
+ d->refWindow(m_sourceItem->window());
+ d->refFromEffectItem(m_hideSource);
+ d->addItemChangeListener(this, QQuickItemPrivate::Geometry);
+ connect(m_sourceItem, SIGNAL(destroyed(QObject*)), this, SLOT(sourceItemDestroyed(QObject*)));
+ } else {
+ qWarning("ShaderEffectSource: sourceItem and ShaderEffectSource must both be children of the same window.");
+ m_sourceItem = 0;
+ }
}
update();
emit sourceItemChanged();
@@ -586,13 +589,24 @@ void QQuickShaderEffectSource::releaseResources()
}
}
+class QQuickShaderSourceAttachedNode : public QObject, public QSGNode
+{
+ Q_OBJECT
+public:
+ Q_SLOT void markTextureDirty() {
+ QSGNode *pn = QSGNode::parent();
+ if (pn) {
+ Q_ASSERT(pn->type() == QSGNode::GeometryNodeType);
+ pn->markDirty(DirtyMaterial);
+ }
+ }
+};
+
QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
if (!m_sourceItem || m_sourceItem->width() <= 0 || m_sourceItem->height() <= 0) {
- if (m_texture) {
+ if (m_texture)
m_texture->setItem(0);
- m_texture->setShaderSourceNode(0);
- }
delete oldNode;
return 0;
}
@@ -658,7 +672,9 @@ QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaint
node = d->sceneGraphContext()->createImageNode();
node->setFlag(QSGNode::UsePreprocess);
node->setTexture(m_texture);
- m_texture->setShaderSourceNode(node);
+ QQuickShaderSourceAttachedNode *attached = new QQuickShaderSourceAttachedNode;
+ node->appendChildNode(attached);
+ connect(m_texture, SIGNAL(updateRequested()), attached, SLOT(markTextureDirty()));
}
// If live and recursive, update continuously.
@@ -698,4 +714,6 @@ void QQuickShaderEffectSource::itemChange(ItemChange change, const ItemChangeDat
QQuickItem::itemChange(change, value);
}
+#include "qquickshadereffectsource.moc"
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp
index a263a890b5..2585caefb5 100644
--- a/src/quick/items/qquicktextcontrol.cpp
+++ b/src/quick/items/qquicktextcontrol.cpp
@@ -435,12 +435,12 @@ void QQuickTextControlPrivate::setClipboardSelection()
}
#endif
-void QQuickTextControlPrivate::_q_emitCursorPosChanged(const QTextCursor &someCursor)
+void QQuickTextControlPrivate::_q_updateCursorPosChanged(const QTextCursor &someCursor)
{
Q_Q(QQuickTextControl);
if (someCursor.isCopyOf(cursor)) {
emit q->cursorPositionChanged();
- cursorRectangleChanged = true;
+ q->updateCursorRectangle(true);
}
}
@@ -578,7 +578,7 @@ QQuickTextControl::QQuickTextControl(QTextDocument *doc, QObject *parent)
qmlobject_connect(layout, QAbstractTextDocumentLayout, SIGNAL(updateBlock(QTextBlock)), this, QQuickTextControl, SIGNAL(updateRequest()));
qmlobject_connect(doc, QTextDocument, SIGNAL(contentsChanged()), this, QQuickTextControl, SIGNAL(textChanged()));
qmlobject_connect(doc, QTextDocument, SIGNAL(contentsChanged()), this, QQuickTextControl, SLOT(_q_updateCurrentCharFormatAndSelection()));
- qmlobject_connect(doc, QTextDocument, SIGNAL(cursorPositionChanged(QTextCursor)), this, QQuickTextControl, SLOT(_q_emitCursorPosChanged(QTextCursor)));
+ qmlobject_connect(doc, QTextDocument, SIGNAL(cursorPositionChanged(QTextCursor)), this, QQuickTextControl, SLOT(_q_updateCursorPosChanged(QTextCursor)));
connect(doc, &QTextDocument::contentsChange, this, &QQuickTextControl::contentsChange);
layout->setProperty("cursorWidth", textCursorWidth);
diff --git a/src/quick/items/qquicktextcontrol_p.h b/src/quick/items/qquicktextcontrol_p.h
index 3cb1590be8..2fe083f1d2 100644
--- a/src/quick/items/qquicktextcontrol_p.h
+++ b/src/quick/items/qquicktextcontrol_p.h
@@ -169,7 +169,7 @@ protected:
private:
Q_DISABLE_COPY(QQuickTextControl)
Q_PRIVATE_SLOT(d_func(), void _q_updateCurrentCharFormatAndSelection())
- Q_PRIVATE_SLOT(d_func(), void _q_emitCursorPosChanged(const QTextCursor &))
+ Q_PRIVATE_SLOT(d_func(), void _q_updateCursorPosChanged(const QTextCursor &))
};
diff --git a/src/quick/items/qquicktextcontrol_p_p.h b/src/quick/items/qquicktextcontrol_p_p.h
index a3b7c7be99..bd07d86f9c 100644
--- a/src/quick/items/qquicktextcontrol_p_p.h
+++ b/src/quick/items/qquicktextcontrol_p_p.h
@@ -88,7 +88,7 @@ public:
void setClipboardSelection();
#endif
- void _q_emitCursorPosChanged(const QTextCursor &someCursor);
+ void _q_updateCursorPosChanged(const QTextCursor &someCursor);
void setBlinkingCursorEnabled(bool enable);
diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp
index f746fe8b1b..67ff79d20f 100644
--- a/src/quick/items/qquicktextnodeengine.cpp
+++ b/src/quick/items/qquicktextnodeengine.cpp
@@ -46,12 +46,37 @@
#include <private/qtextdocumentlayout_p.h>
#include <private/qtextimagehandler_p.h>
#include <private/qrawfont_p.h>
+#include <private/qglyphrun_p.h>
QT_BEGIN_NAMESPACE
+QQuickTextNodeEngine::BinaryTreeNode::BinaryTreeNode(const QGlyphRun &g,
+ SelectionState selState,
+ const QRectF &brect,
+ const QQuickTextNode::Decorations &decs,
+ const QColor &c,
+ const QColor &bc,
+ const QPointF &pos, qreal a)
+ : glyphRun(g)
+ , boundingRect(brect)
+ , selectionState(selState)
+ , clipNode(0)
+ , decorations(decs)
+ , color(c)
+ , backgroundColor(bc)
+ , position(pos)
+ , ascent(a)
+ , leftChildIndex(-1)
+ , rightChildIndex(-1)
+{
+ QGlyphRunPrivate *d = QGlyphRunPrivate::get(g);
+ ranges.append(qMakePair(d->textRangeStart, d->textRangeEnd));
+}
+
+
void QQuickTextNodeEngine::BinaryTreeNode::insert(QVarLengthArray<BinaryTreeNode, 16> *binaryTree, const QGlyphRun &glyphRun, SelectionState selectionState,
QQuickTextNode::Decorations decorations, const QColor &textColor,
- const QColor &backgroundColor, const QPointF &position, int rangeStart, int rangeEnd)
+ const QColor &backgroundColor, const QPointF &position)
{
QRectF searchRect = glyphRun.boundingRect();
searchRect.translate(position);
@@ -65,8 +90,14 @@ void QQuickTextNodeEngine::BinaryTreeNode::insert(QVarLengthArray<BinaryTreeNode
decorations |= (backgroundColor.isValid() ? QQuickTextNode::Background : QQuickTextNode::NoDecoration);
qreal ascent = glyphRun.rawFont().ascent();
- insert(binaryTree, BinaryTreeNode(glyphRun, selectionState, searchRect, decorations,
- textColor, backgroundColor, position, ascent, rangeStart, rangeEnd));
+ insert(binaryTree, BinaryTreeNode(glyphRun,
+ selectionState,
+ searchRect,
+ decorations,
+ textColor,
+ backgroundColor,
+ position,
+ ascent));
}
void QQuickTextNodeEngine::BinaryTreeNode::insert(QVarLengthArray<BinaryTreeNode, 16> *binaryTree, const BinaryTreeNode &binaryTreeNode)
@@ -441,19 +472,27 @@ void QQuickTextNodeEngine::addTextObject(const QPointF &position, const QTextCha
}
}
-void QQuickTextNodeEngine::addUnselectedGlyphs(const QGlyphRun &glyphRun, int rangeStart, int rangeEnd)
+void QQuickTextNodeEngine::addUnselectedGlyphs(const QGlyphRun &glyphRun)
{
- BinaryTreeNode::insert(&m_currentLineTree, glyphRun, Unselected,
- QQuickTextNode::NoDecoration, m_textColor, m_backgroundColor, m_position,
- rangeStart, rangeEnd);
+ BinaryTreeNode::insert(&m_currentLineTree,
+ glyphRun,
+ Unselected,
+ QQuickTextNode::NoDecoration,
+ m_textColor,
+ m_backgroundColor,
+ m_position);
}
-void QQuickTextNodeEngine::addSelectedGlyphs(const QGlyphRun &glyphRun, int rangeStart, int rangeEnd)
+void QQuickTextNodeEngine::addSelectedGlyphs(const QGlyphRun &glyphRun)
{
int currentSize = m_currentLineTree.size();
- BinaryTreeNode::insert(&m_currentLineTree, glyphRun, Selected,
- QQuickTextNode::NoDecoration, m_textColor, m_backgroundColor, m_position,
- rangeStart, rangeEnd);
+ BinaryTreeNode::insert(&m_currentLineTree,
+ glyphRun,
+ Selected,
+ QQuickTextNode::NoDecoration,
+ m_textColor,
+ m_backgroundColor,
+ m_position);
m_hasSelection = m_hasSelection || m_currentLineTree.size() > currentSize;
}
@@ -526,7 +565,7 @@ void QQuickTextNodeEngine::addGlyphsInRange(int rangeStart, int rangeLength,
QList<QGlyphRun> glyphRuns = line.glyphRuns(rangeStart, rangeLength);
for (int j=0; j<glyphRuns.size(); ++j) {
const QGlyphRun &glyphRun = glyphRuns.at(j);
- addUnselectedGlyphs(glyphRun, rangeStart, rangeEnd - 1);
+ addUnselectedGlyphs(glyphRun);
}
} else {
if (rangeStart < selectionStart) {
@@ -534,7 +573,7 @@ void QQuickTextNodeEngine::addGlyphsInRange(int rangeStart, int rangeLength,
QList<QGlyphRun> glyphRuns = line.glyphRuns(rangeStart, length);
for (int j=0; j<glyphRuns.size(); ++j) {
const QGlyphRun &glyphRun = glyphRuns.at(j);
- addUnselectedGlyphs(glyphRun, rangeStart, rangeStart + length - 1);
+ addUnselectedGlyphs(glyphRun);
}
}
@@ -545,8 +584,8 @@ void QQuickTextNodeEngine::addGlyphsInRange(int rangeStart, int rangeLength,
for (int j=0; j<glyphRuns.size(); ++j) {
const QGlyphRun &glyphRun = glyphRuns.at(j);
- addSelectedGlyphs(glyphRun, start, start + length - 1);
- addUnselectedGlyphs(glyphRun, start, start + length - 1);
+ addSelectedGlyphs(glyphRun);
+ addUnselectedGlyphs(glyphRun);
}
}
@@ -556,7 +595,7 @@ void QQuickTextNodeEngine::addGlyphsInRange(int rangeStart, int rangeLength,
QList<QGlyphRun> glyphRuns = line.glyphRuns(start, length);
for (int j=0; j<glyphRuns.size(); ++j) {
const QGlyphRun &glyphRun = glyphRuns.at(j);
- addUnselectedGlyphs(glyphRun, start, start + length - 1);
+ addUnselectedGlyphs(glyphRun);
}
}
}
@@ -927,7 +966,7 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText
QList<QGlyphRun> glyphRuns = layout.glyphRuns();
for (int i=0; i<glyphRuns.size(); ++i)
- addUnselectedGlyphs(glyphRuns.at(i), 0, layout.text().length() - 1);
+ addUnselectedGlyphs(glyphRuns.at(i));
}
}
diff --git a/src/quick/items/qquicktextnodeengine_p.h b/src/quick/items/qquicktextnodeengine_p.h
index 142375b5a3..f0d52683c6 100644
--- a/src/quick/items/qquicktextnodeengine_p.h
+++ b/src/quick/items/qquicktextnodeengine_p.h
@@ -75,12 +75,7 @@ public:
BinaryTreeNode(const QGlyphRun &g, SelectionState selState, const QRectF &brect,
const QQuickTextNode::Decorations &decs, const QColor &c, const QColor &bc,
- const QPointF &pos, qreal a, int rangeStart, int rangeEnd)
- : glyphRun(g), boundingRect(brect), selectionState(selState), clipNode(0), decorations(decs)
- , color(c), backgroundColor(bc), position(pos), ascent(a), leftChildIndex(-1), rightChildIndex(-1)
- {
- ranges.append(qMakePair(rangeStart, rangeEnd));
- }
+ const QPointF &pos, qreal a);
QGlyphRun glyphRun;
QRectF boundingRect;
@@ -102,8 +97,7 @@ public:
{ insert(binaryTree, BinaryTreeNode(rect, image, selectionState, ascent)); }
static void insert(QVarLengthArray<BinaryTreeNode, 16> *binaryTree, const QGlyphRun &glyphRun, SelectionState selectionState,
- QQuickTextNode::Decorations decorations, const QColor &textColor, const QColor &backgroundColor, const QPointF &position,
- int rangeStart, int rangeEnd);
+ QQuickTextNode::Decorations decorations, const QColor &textColor, const QColor &backgroundColor, const QPointF &position);
static void insert(QVarLengthArray<BinaryTreeNode, 16> *binaryTree, const BinaryTreeNode &binaryTreeNode);
static void inOrder(const QVarLengthArray<BinaryTreeNode, 16> &binaryTree, QVarLengthArray<int> *sortedIndexes, int currentIndex = 0);
};
@@ -138,8 +132,8 @@ public:
SelectionState selectionState,
QTextDocument *textDocument, int pos,
QTextFrameFormat::Position layoutPosition = QTextFrameFormat::InFlow);
- void addSelectedGlyphs(const QGlyphRun &glyphRun, int rangeStart, int rangeEnd);
- void addUnselectedGlyphs(const QGlyphRun &glyphRun, int rangeStart, int rangeEnd);
+ void addSelectedGlyphs(const QGlyphRun &glyphRun);
+ void addUnselectedGlyphs(const QGlyphRun &glyphRun);
void addGlyphsInRange(int rangeStart, int rangeEnd,
const QColor &color, const QColor &backgroundColor,
int selectionStart, int selectionEnd);
diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp
index 91a6468593..a55d056c75 100644
--- a/src/quick/items/qquickview.cpp
+++ b/src/quick/items/qquickview.cpp
@@ -594,7 +594,7 @@ void QQuickView::resizeEvent(QResizeEvent *e)
/*! \reimp */
void QQuickView::keyPressEvent(QKeyEvent *e)
{
- Q_QUICK_PROFILE(addEvent<QQuickProfiler::Key>());
+ Q_QUICK_INPUT_PROFILE(addEvent<QQuickProfiler::Key>());
QQuickWindow::keyPressEvent(e);
}
@@ -602,7 +602,7 @@ void QQuickView::keyPressEvent(QKeyEvent *e)
/*! \reimp */
void QQuickView::keyReleaseEvent(QKeyEvent *e)
{
- Q_QUICK_PROFILE(addEvent<QQuickProfiler::Key>());
+ Q_QUICK_INPUT_PROFILE(addEvent<QQuickProfiler::Key>());
QQuickWindow::keyReleaseEvent(e);
}
@@ -610,7 +610,7 @@ void QQuickView::keyReleaseEvent(QKeyEvent *e)
/*! \reimp */
void QQuickView::mouseMoveEvent(QMouseEvent *e)
{
- Q_QUICK_PROFILE(addEvent<QQuickProfiler::Mouse>());
+ Q_QUICK_INPUT_PROFILE(addEvent<QQuickProfiler::Mouse>());
QQuickWindow::mouseMoveEvent(e);
}
@@ -618,7 +618,7 @@ void QQuickView::mouseMoveEvent(QMouseEvent *e)
/*! \reimp */
void QQuickView::mousePressEvent(QMouseEvent *e)
{
- Q_QUICK_PROFILE(addEvent<QQuickProfiler::Mouse>());
+ Q_QUICK_INPUT_PROFILE(addEvent<QQuickProfiler::Mouse>());
QQuickWindow::mousePressEvent(e);
}
@@ -626,7 +626,7 @@ void QQuickView::mousePressEvent(QMouseEvent *e)
/*! \reimp */
void QQuickView::mouseReleaseEvent(QMouseEvent *e)
{
- Q_QUICK_PROFILE(addEvent<QQuickProfiler::Mouse>());
+ Q_QUICK_INPUT_PROFILE(addEvent<QQuickProfiler::Mouse>());
QQuickWindow::mouseReleaseEvent(e);
}
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index ca0a81f2f4..5548017ddc 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -1654,8 +1654,8 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce
// Leaving from previous hovered items until we reach the item or one of its ancestors.
while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems[0])) {
- sendHoverEvent(QEvent::HoverLeave, hoverItems[0], scenePos, lastScenePos, modifiers, accepted);
- hoverItems.removeFirst();
+ QQuickItem *hoverLeaveItem = hoverItems.takeFirst();
+ sendHoverEvent(QEvent::HoverLeave, hoverLeaveItem, scenePos, lastScenePos, modifiers, accepted);
}
if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item
@@ -2922,7 +2922,7 @@ void QQuickWindow::setTransientParent_helper(QQuickWindow *window)
QOpenGLContext *QQuickWindow::openglContext() const
{
Q_D(const QQuickWindow);
- return d->context->openglContext();
+ return d->context ? d->context->openglContext() : 0;
}
/*!
@@ -3530,7 +3530,7 @@ void QQuickWindow::setColor(const QColor &color)
}
d->clearColor = color;
emit colorChanged(color);
- d->dirtyItem(contentItem());
+ update();
}
QColor QQuickWindow::color() const
@@ -3914,11 +3914,6 @@ void QQuickWindow::scheduleRenderJob(QRunnable *job, RenderStage stage)
d->renderJobMutex.unlock();
}
-QQuickWindowAttached *QQuickWindow::qmlAttachedProperties(QObject *object)
-{
- return new QQuickWindowAttached(object);
-}
-
void QQuickWindowPrivate::runAndClearJobs(QList<QRunnable *> *jobs)
{
renderJobMutex.lock();
diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h
index 82f2e29d9d..8d75a4767c 100644
--- a/src/quick/items/qquickwindow.h
+++ b/src/quick/items/qquickwindow.h
@@ -143,8 +143,6 @@ public:
void scheduleRenderJob(QRunnable *job, RenderStage schedule);
- static QQuickWindowAttached *qmlAttachedProperties(QObject *object);
-
Q_SIGNALS:
void frameSwapped();
Q_REVISION(2) void openglContextCreated(QOpenGLContext *context);
@@ -209,7 +207,6 @@ private:
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QQuickWindow *)
-QML_DECLARE_TYPEINFO(QQuickWindow, QML_HAS_ATTACHED_PROPERTIES)
#endif // QQUICKWINDOW_H
diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp
index dbd0628db2..bf41bc136f 100644
--- a/src/quick/items/qquickwindowmodule.cpp
+++ b/src/quick/items/qquickwindowmodule.cpp
@@ -79,6 +79,11 @@ public:
QQuickWindow::setVisibility(visibility);
}
+ static QQuickWindowAttached *qmlAttachedProperties(QObject *object)
+ {
+ return new QQuickWindowAttached(object);
+ }
+
Q_SIGNALS:
void visibleChanged(bool arg);
void visibilityChanged(QWindow::Visibility visibility);
@@ -166,16 +171,13 @@ void QQuickWindowModule::defineModule()
{
const char uri[] = "QtQuick.Window";
- // Since Window is both an attached property and a createable type,
- // the attached property declaration must come first so that it can
- // be overridden below.
- qmlRegisterUncreatableType<QQuickWindow>(uri, 2, 2, "Window", QQuickWindow::tr("Window is available via attached properties"));
qmlRegisterType<QQuickWindow>(uri, 2, 0, "Window");
qmlRegisterRevision<QWindow,1>(uri, 2, 1);
qmlRegisterRevision<QWindow,2>(uri, 2, 2);
qmlRegisterRevision<QQuickWindow,1>(uri, 2, 1);//Type moved to a subclass, but also has new members
qmlRegisterRevision<QQuickWindow,2>(uri, 2, 2);
qmlRegisterType<QQuickWindowQmlImpl>(uri, 2, 1, "Window");
+ qmlRegisterType<QQuickWindowQmlImpl,1>(uri, 2, 2, "Window");
qmlRegisterUncreatableType<QQuickScreen>(uri, 2, 0, "Screen", QStringLiteral("Screen can only be used via the attached property."));
}
@@ -183,3 +185,4 @@ void QQuickWindowModule::defineModule()
QT_END_NAMESPACE
+QML_DECLARE_TYPEINFO(QQuickWindowQmlImpl, QML_HAS_ATTACHED_PROPERTIES)
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index 173858b21d..ac45cf70db 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -63,15 +63,19 @@ extern QByteArray qsgShaderRewriter_insertZAttributes(const char *input, QSurfac
namespace QSGBatchRenderer
{
-const bool debug_render = qgetenv("QSG_RENDERER_DEBUG").contains("render");
-const bool debug_build = qgetenv("QSG_RENDERER_DEBUG").contains("build");
-const bool debug_change = qgetenv("QSG_RENDERER_DEBUG").contains("change");
-const bool debug_upload = qgetenv("QSG_RENDERER_DEBUG").contains("upload");
-const bool debug_roots = qgetenv("QSG_RENDERER_DEBUG").contains("roots");
-const bool debug_dump = qgetenv("QSG_RENDERER_DEBUG").contains("dump");
-const bool debug_noalpha = qgetenv("QSG_RENDERER_DEBUG").contains("noalpha");
-const bool debug_noopaque = qgetenv("QSG_RENDERER_DEBUG").contains("noopaque");
-const bool debug_noclip = qgetenv("QSG_RENDERER_DEBUG").contains("noclip");
+#define DECLARE_DEBUG_VAR(variable) \
+ static bool debug_ ## variable() \
+ { static bool value = qgetenv("QSG_RENDERER_DEBUG").contains(QT_STRINGIFY(variable)); return value; }
+DECLARE_DEBUG_VAR(render)
+DECLARE_DEBUG_VAR(build)
+DECLARE_DEBUG_VAR(change)
+DECLARE_DEBUG_VAR(upload)
+DECLARE_DEBUG_VAR(roots)
+DECLARE_DEBUG_VAR(dump)
+DECLARE_DEBUG_VAR(noalpha)
+DECLARE_DEBUG_VAR(noopaque)
+DECLARE_DEBUG_VAR(noclip)
+#undef DECLARE_DEBUG_VAR
static QElapsedTimer qsg_renderer_timer;
@@ -268,10 +272,10 @@ void Updater::updateStates(QSGNode *n)
Node *sn = renderer->m_nodes.value(n, 0);
Q_ASSERT(sn);
- if (Q_UNLIKELY(debug_roots))
+ if (Q_UNLIKELY(debug_roots()))
qsg_dumpShadowRoots(sn);
- if (Q_UNLIKELY(debug_build)) {
+ if (Q_UNLIKELY(debug_build())) {
qDebug() << "Updater::updateStates()";
if (sn->dirtyState & (QSGNode::DirtyNodeAdded << 16))
qDebug() << " - nodes have been added";
@@ -785,7 +789,7 @@ Renderer::Renderer(QSGRenderContext *ctx)
if (ok)
m_batchVertexThreshold = threshold;
}
- if (Q_UNLIKELY(debug_build || debug_render)) {
+ if (Q_UNLIKELY(debug_build() || debug_render())) {
qDebug() << "Batch thresholds: nodes:" << m_batchNodeThreshold << " vertices:" << m_batchVertexThreshold;
qDebug() << "Using buffer strategy:" << (m_bufferStrategy == GL_STATIC_DRAW ? "static" : (m_bufferStrategy == GL_DYNAMIC_DRAW ? "dynamic" : "stream"));
}
@@ -1048,7 +1052,7 @@ void Renderer::nodeWasRemoved(Node *node)
void Renderer::turnNodeIntoBatchRoot(Node *node)
{
- if (Q_UNLIKELY(debug_change)) qDebug() << " - new batch root";
+ if (Q_UNLIKELY(debug_change())) qDebug() << " - new batch root";
m_rebuild |= FullRebuild;
node->isBatchRoot = true;
node->becameBatchRoot = true;
@@ -1069,7 +1073,7 @@ void Renderer::turnNodeIntoBatchRoot(Node *node)
void Renderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state)
{
- if (Q_UNLIKELY(debug_change)) {
+ if (Q_UNLIKELY(debug_change())) {
QDebug debug = qDebug();
debug << "dirty:";
if (state & QSGNode::DirtyGeometry)
@@ -1616,7 +1620,7 @@ void Renderer::prepareAlphaBatches()
void Renderer::uploadMergedElement(Element *e, int vaOffset, char **vertexData, char **zData, char **indexData, quint16 *iBase, int *indexCount)
{
- if (Q_UNLIKELY(debug_upload)) qDebug() << " - uploading element:" << e << e->node << (void *) *vertexData << (qintptr) (*zData - *vertexData) << (qintptr) (*indexData - *vertexData);
+ if (Q_UNLIKELY(debug_upload())) qDebug() << " - uploading element:" << e << e->node << (void *) *vertexData << (qintptr) (*zData - *vertexData) << (qintptr) (*indexData - *vertexData);
QSGGeometry *g = e->node->geometry();
const QMatrix4x4 &localx = *e->node->matrix();
@@ -1689,17 +1693,17 @@ void Renderer::uploadBatch(Batch *b)
{
// Early out if nothing has changed in this batch..
if (!b->needsUpload) {
- if (Q_UNLIKELY(debug_upload)) qDebug() << " Batch:" << b << "already uploaded...";
+ if (Q_UNLIKELY(debug_upload())) qDebug() << " Batch:" << b << "already uploaded...";
return;
}
if (!b->first) {
- if (Q_UNLIKELY(debug_upload)) qDebug() << " Batch:" << b << "is invalid...";
+ if (Q_UNLIKELY(debug_upload())) qDebug() << " Batch:" << b << "is invalid...";
return;
}
if (b->isRenderNode) {
- if (Q_UNLIKELY(debug_upload)) qDebug() << " Batch: " << b << "is a render node...";
+ if (Q_UNLIKELY(debug_upload())) qDebug() << " Batch: " << b << "is a render node...";
return;
}
@@ -1778,7 +1782,7 @@ void Renderer::uploadBatch(Batch *b)
#endif
map(&b->vbo, bufferSize);
- if (Q_UNLIKELY(debug_upload)) qDebug() << " - batch" << b << " first:" << b->first << " root:"
+ if (Q_UNLIKELY(debug_upload())) qDebug() << " - batch" << b << " first:" << b->first << " root:"
<< b->root << " merged:" << b->merged << " positionAttribute" << b->positionAttribute
<< " vbo:" << b->vbo.id << ":" << b->vbo.size;
@@ -1844,7 +1848,7 @@ void Renderer::uploadBatch(Batch *b)
}
}
- if (Q_UNLIKELY(debug_upload)) {
+ if (Q_UNLIKELY(debug_upload())) {
const char *vd = b->vbo.data;
qDebug() << " -- Vertex Data, count:" << b->vertexCount << " - " << g->sizeOfVertex() << "bytes/vertex";
for (int i=0; i<b->vertexCount; ++i) {
@@ -1875,9 +1879,12 @@ void Renderer::uploadBatch(Batch *b)
vd += g->sizeOfVertex();
}
- const quint16 *id = (const quint16 *) (b->vbo.data
- + b->vertexCount * g->sizeOfVertex()
- + (b->merged ? b->vertexCount * sizeof(float) : 0));
+ const quint16 *id =
+#ifdef QSG_SEPARATE_INDEX_BUFFER
+ (const quint16 *) (b->ibo.data);
+#else
+ (const quint16 *) (b->vbo.data + b->drawSets.at(0).indices);
+#endif
{
QDebug iDump = qDebug();
iDump << " -- Index Data, count:" << b->indexCount;
@@ -1899,11 +1906,11 @@ void Renderer::uploadBatch(Batch *b)
unmap(&b->ibo, true);
#endif
- if (Q_UNLIKELY(debug_upload)) qDebug() << " --- vertex/index buffers unmapped, batch upload completed...";
+ if (Q_UNLIKELY(debug_upload())) qDebug() << " --- vertex/index buffers unmapped, batch upload completed...";
b->needsUpload = false;
- if (Q_UNLIKELY(debug_render))
+ if (Q_UNLIKELY(debug_render()))
b->uploadedThisFrame = true;
}
@@ -2035,7 +2042,7 @@ Renderer::ClipType Renderer::updateStencilClip(const QSGClipNode *clip)
void Renderer::updateClip(const QSGClipNode *clipList, const Batch *batch)
{
- if (clipList != m_currentClip && Q_LIKELY(!debug_noclip)) {
+ if (clipList != m_currentClip && Q_LIKELY(!debug_noclip())) {
m_currentClip = clipList;
// updateClip sets another program, so force-reactivate our own
if (m_currentShader)
@@ -2114,7 +2121,7 @@ void Renderer::renderMergedBatch(const Batch *batch)
Element *e = batch->first;
Q_ASSERT(e);
- if (Q_UNLIKELY(debug_render)) {
+ if (Q_UNLIKELY(debug_render())) {
QDebug debug = qDebug();
debug << " -"
<< batch
@@ -2223,7 +2230,7 @@ void Renderer::renderUnmergedBatch(const Batch *batch)
Element *e = batch->first;
Q_ASSERT(e);
- if (Q_UNLIKELY(debug_render)) {
+ if (Q_UNLIKELY(debug_render())) {
qDebug() << " -"
<< batch
<< (batch->uploadedThisFrame ? "[ upload]" : "[retained]")
@@ -2353,7 +2360,7 @@ void Renderer::renderUnmergedBatch(const Batch *batch)
void Renderer::renderBatches()
{
- if (Q_UNLIKELY(debug_render)) {
+ if (Q_UNLIKELY(debug_render())) {
qDebug().nospace() << "Rendering:" << endl
<< " -> Opaque: " << qsg_countNodesInBatches(m_opaqueBatches) << " nodes in " << m_opaqueBatches.size() << " batches..." << endl
<< " -> Alpha: " << qsg_countNodesInBatches(m_alphaBatches) << " nodes in " << m_alphaBatches.size() << " batches...";
@@ -2386,8 +2393,8 @@ void Renderer::renderBatches()
m_currentProgram = 0;
m_currentClip = 0;
- bool renderOpaque = !debug_noopaque;
- bool renderAlpha = !debug_noalpha;
+ bool renderOpaque = !debug_noopaque();
+ bool renderAlpha = !debug_noalpha();
if (Q_LIKELY(renderOpaque)) {
for (int i=0; i<m_opaqueBatches.size(); ++i) {
@@ -2463,12 +2470,12 @@ void Renderer::preprocess()
void Renderer::render()
{
- if (Q_UNLIKELY(debug_dump)) {
+ if (Q_UNLIKELY(debug_dump())) {
qDebug("\n");
QSGNodeDumper::dump(rootNode());
}
- if (Q_UNLIKELY(debug_render || debug_build)) {
+ if (Q_UNLIKELY(debug_render() || debug_build())) {
QByteArray type("rebuild:");
if (m_rebuild == 0)
@@ -2495,7 +2502,7 @@ void Renderer::render()
buildRenderListsForTaggedRoots();
m_rebuild |= BuildBatches;
- if (Q_UNLIKELY(debug_build)) {
+ if (Q_UNLIKELY(debug_build())) {
qDebug() << "Opaque render lists" << (complete ? "(complete)" : "(partial)") << ":";
for (int i=0; i<m_opaqueRenderList.size(); ++i) {
Element *e = m_opaqueRenderList.at(i);
@@ -2522,7 +2529,7 @@ void Renderer::render()
prepareOpaqueBatches();
prepareAlphaBatches();
- if (Q_UNLIKELY(debug_build)) {
+ if (Q_UNLIKELY(debug_build())) {
qDebug() << "Opaque Batches:";
for (int i=0; i<m_opaqueBatches.size(); ++i) {
Batch *b = m_opaqueBatches.at(i);
@@ -2558,11 +2565,11 @@ void Renderer::render()
}
- if (Q_UNLIKELY(debug_upload)) qDebug() << "Uploading Opaque Batches:";
+ if (Q_UNLIKELY(debug_upload())) qDebug() << "Uploading Opaque Batches:";
for (int i=0; i<m_opaqueBatches.size(); ++i)
uploadBatch(m_opaqueBatches.at(i));
- if (Q_UNLIKELY(debug_upload)) qDebug() << "Uploading Alpha Batches:";
+ if (Q_UNLIKELY(debug_upload())) qDebug() << "Uploading Alpha Batches:";
for (int i=0; i<m_alphaBatches.size(); ++i)
uploadBatch(m_alphaBatches.at(i));
@@ -2581,7 +2588,7 @@ void Renderer::render()
void Renderer::renderRenderNode(Batch *batch)
{
- if (Q_UNLIKELY(debug_render))
+ if (Q_UNLIKELY(debug_render()))
qDebug() << " -" << batch << "rendernode";
Q_ASSERT(batch->first->isRenderNode);
diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp
index db32f656e1..e0b96a45b6 100644
--- a/src/quick/scenegraph/qsgadaptationlayer.cpp
+++ b/src/quick/scenegraph/qsgadaptationlayer.cpp
@@ -338,25 +338,4 @@ void QSGNodeVisitorEx::visitChildren(QSGNode *node)
}
}
-void QSGLayer::markDirtyTextureLater()
-{
- QCoreApplication::postEvent(this, new QEvent(static_cast<QEvent::Type>(markDirtyEventType())));
-}
-
-void QSGLayer::customEvent(QEvent *event)
-{
- if (event->type() == markDirtyEventType())
- markDirtyTexture();
- else
- QObject::customEvent(event);
-}
-
-int QSGLayer::markDirtyEventType()
-{
- static int type = QEvent::None;
- if (type == QEvent::None)
- type = QEvent::registerEventType();
- return type;
-}
-
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h
index 71033bd6d0..a63299fcde 100644
--- a/src/quick/scenegraph/qsgadaptationlayer_p.h
+++ b/src/quick/scenegraph/qsgadaptationlayer_p.h
@@ -198,7 +198,6 @@ class Q_QUICK_EXPORT QSGLayer : public QSGDynamicTexture
Q_OBJECT
public:
virtual void setItem(QSGNode *item) = 0;
- virtual void setShaderSourceNode(QSGNode *node) = 0;
virtual void setRect(const QRectF &rect) = 0;
virtual void setSize(const QSize &size) = 0;
virtual void scheduleUpdate() = 0;
@@ -211,17 +210,9 @@ public:
Q_SLOT virtual void markDirtyTexture() = 0;
Q_SLOT virtual void invalidated() = 0;
- Q_SLOT void markDirtyTextureLater();
-
Q_SIGNALS:
void updateRequested();
void scheduledUpdateCompleted();
-
-protected:
- virtual void customEvent(QEvent *);
-
-private:
- int markDirtyEventType();
};
class Q_QUICK_PRIVATE_EXPORT QSGGlyphNode : public QSGVisitableNode
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp
index e7b37e50d2..b87ab3686f 100644
--- a/src/quick/scenegraph/qsgcontext.cpp
+++ b/src/quick/scenegraph/qsgcontext.cpp
@@ -50,6 +50,7 @@
#include <QtQuick/private/qquickpixmapcache_p.h>
#include <QGuiApplication>
+#include <QScreen>
#include <QOpenGLContext>
#include <QQuickWindow>
#include <QtGui/qopenglframebufferobject.h>
@@ -58,6 +59,7 @@
#include <QtQuick/private/qsgtexture_p.h>
#include <QtGui/private/qguiapplication_p.h>
+#include <QtCore/private/qabstractanimation_p.h>
#include <qpa/qplatformintegration.h>
#include <qpa/qplatformsharedgraphicscache.h>
@@ -134,6 +136,135 @@ public:
bool distanceFieldAntialiasingDecided;
};
+static bool qsg_useConsistentTiming()
+{
+ static int use = -1;
+ if (use < 0) {
+ QByteArray fixed = qgetenv("QSG_FIXED_ANIMATION_STEP");
+ use = !(fixed.isEmpty() || fixed == "no");
+ qCDebug(QSG_LOG_INFO, "Using %s", bool(use) ? "fixed animation steps" : "sg animation driver");
+ }
+ return bool(use);
+}
+
+class QSGAnimationDriver : public QAnimationDriver
+{
+ Q_OBJECT
+public:
+ enum Mode {
+ VSyncMode,
+ TimerMode
+ };
+
+ QSGAnimationDriver(QObject *parent)
+ : QAnimationDriver(parent)
+ , m_time(0)
+ , m_vsync(0)
+ , m_mode(VSyncMode)
+ , m_bad(0)
+ , m_reallyBad(0)
+ , m_good(0)
+ {
+ QScreen *screen = QGuiApplication::primaryScreen();
+ if (screen && !qsg_useConsistentTiming()) {
+ m_vsync = 1000.0 / screen->refreshRate();
+ if (m_vsync <= 0)
+ m_mode = TimerMode;
+ } else {
+ m_mode = TimerMode;
+ if (qsg_useConsistentTiming())
+ QUnifiedTimer::instance(true)->setConsistentTiming(true);
+ }
+ if (m_mode == VSyncMode)
+ qCDebug(QSG_LOG_INFO, "Animation Driver: using vsync: %.2f ms", m_vsync);
+ else
+ qCDebug(QSG_LOG_INFO, "Animation Driver: using walltime");
+ }
+
+ void start() Q_DECL_OVERRIDE
+ {
+ m_time = 0;
+ m_timer.start();
+ QAnimationDriver::start();
+ }
+
+ qint64 elapsed() const Q_DECL_OVERRIDE
+ {
+ return m_mode == VSyncMode
+ ? qint64(m_time)
+ : QAnimationDriver::elapsed();
+ }
+
+ void advance() Q_DECL_OVERRIDE
+ {
+ qint64 delta = m_timer.restart();
+
+ if (m_mode == VSyncMode) {
+ // If a frame is skipped, either because rendering was slow or because
+ // the QML was slow, we accept it and continue advancing with a single
+ // vsync tick. The reason for this is that by the time we notice this
+ // on the GUI thread, the temporal distortion has already gone to screen
+ // and by catching up, we will introduce a second distortion which will
+ // worse. We accept that the animation time falls behind wall time because
+ // it comes out looking better.
+ // Only when multiple bad frames are hit in a row, do we consider
+ // switching. A few really bad frames and we switch right away. For frames
+ // just above the vsync delta, we tolerate a bit more since a buffered
+ // driver can have vsync deltas on the form: 4, 21, 21, 2, 23, 16, and
+ // still manage to put the frames to screen at 16 ms intervals. In addition
+ // to that, we tolerate a 25% margin of error on the value of m_vsync
+ // reported from the system as this value is often not precise.
+
+ m_time += m_vsync;
+
+ if (delta > m_vsync * 5) {
+ ++m_reallyBad;
+ ++m_bad;
+ } else if (delta > m_vsync * 1.25) {
+ ++m_bad;
+ } else {
+ // reset counters on a good frame.
+ m_reallyBad = 0;
+ m_bad = 0;
+ }
+
+ // rational for the 3 and 50. If we have several really bad frames
+ // in a row, that would indicate a huge performance problem and we should
+ // switch right away. For the case of m_bad, we're a bit more tolerant.
+ if (m_reallyBad > 3 || m_bad > 50) {
+ m_mode = TimerMode;
+ qCDebug(QSG_LOG_INFO, "animation driver switched to timer mode");
+ }
+
+ } else {
+ if (delta < 1.25 * m_vsync) {
+ ++m_good;
+ } else {
+ m_good = 0;
+ }
+
+ // We've been solid for a while, switch back to vsync mode. Tolerance
+ // for switching back is lower than switching to timer mode, as we
+ // want to stay in vsync mode as much as possible.
+ if (m_good > 10 && !qsg_useConsistentTiming()) {
+ m_time = elapsed();
+ m_mode = VSyncMode;
+ qCDebug(QSG_LOG_INFO, "animation driver switched to vsync mode");
+ }
+ }
+
+ advanceAnimation();
+ }
+
+ float m_time;
+ float m_vsync;
+ Mode m_mode;
+ QElapsedTimer m_timer;
+ int m_bad;
+ int m_reallyBad;
+ int m_good;
+};
+
class QSGTextureCleanupEvent : public QEvent
{
public:
@@ -389,7 +520,7 @@ bool QSGContext::isDistanceFieldEnabled() const
QAnimationDriver *QSGContext::createAnimationDriver(QObject *parent)
{
- return new QAnimationDriver(parent);
+ return new QSGAnimationDriver(parent);
}
QSGRenderContext::QSGRenderContext(QSGContext *context)
@@ -730,4 +861,6 @@ void QSGRenderContext::initialize(QSGMaterialShader *shader)
shader->initialize();
}
+#include "qsgcontext.moc"
+
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
index 16feafe02f..802c92be9f 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -128,28 +128,8 @@ void QSGTextMaskShader::updateState(const RenderState &state, QSGMaterial *newEf
}
}
- if (state.isMatrixDirty()) {
- QMatrix4x4 transform = state.modelViewMatrix();
- qreal xTranslation = transform(0, 3);
- qreal yTranslation = transform(1, 3);
-
- // Remove translation and check identity to see if matrix is only translating.
- // If it is, we can round the translation to make sure the text is pixel aligned,
- // which is the only thing that works with GL_NEAREST filtering. Adding rotations
- // and scales to native rendered text is not a prioritized use case, since the
- // default rendering type is designed for that.
- transform(0, 3) = 0.0;
- transform(1, 3) = 0.0;
- if (transform.isIdentity()) {
- transform(0, 3) = qRound(xTranslation);
- transform(1, 3) = qRound(yTranslation);
-
- transform = state.projectionMatrix() * transform;
- program()->setUniformValue(m_matrix_id, transform);
- } else {
- program()->setUniformValue(m_matrix_id, state.combinedMatrix());
- }
- }
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, state.combinedMatrix());
}
class QSG8BitTextMaskShader : public QSGTextMaskShader
diff --git a/src/quick/scenegraph/qsgdefaultlayer.cpp b/src/quick/scenegraph/qsgdefaultlayer.cpp
index 29f125e0be..2d114aebd5 100644
--- a/src/quick/scenegraph/qsgdefaultlayer.cpp
+++ b/src/quick/scenegraph/qsgdefaultlayer.cpp
@@ -88,7 +88,6 @@ namespace
QSGDefaultLayer::QSGDefaultLayer(QSGRenderContext *context)
: QSGLayer()
, m_item(0)
- , m_shaderSourceNode(0)
, m_device_pixel_ratio(1)
, m_format(GL_RGBA)
, m_renderer(0)
@@ -259,11 +258,8 @@ void QSGDefaultLayer::scheduleUpdate()
if (m_grab)
return;
m_grab = true;
- if (m_dirtyTexture) {
+ if (m_dirtyTexture)
emit updateRequested();
- if (m_shaderSourceNode)
- m_shaderSourceNode->markDirty(QSGNode::DirtyMaterial);
- }
}
void QSGDefaultLayer::setRecursive(bool recursive)
@@ -274,11 +270,8 @@ void QSGDefaultLayer::setRecursive(bool recursive)
void QSGDefaultLayer::markDirtyTexture()
{
m_dirtyTexture = true;
- if (m_live || m_grab) {
+ if (m_live || m_grab)
emit updateRequested();
- if (m_shaderSourceNode)
- m_shaderSourceNode->markDirty(QSGNode::DirtyMaterial);
- }
}
void QSGDefaultLayer::grab()
@@ -299,7 +292,7 @@ void QSGDefaultLayer::grab()
if (!m_renderer) {
m_renderer = m_context->createRenderer();
- connect(m_renderer, SIGNAL(sceneGraphChanged()), this, SLOT(markDirtyTextureLater()));
+ connect(m_renderer, SIGNAL(sceneGraphChanged()), this, SLOT(markDirtyTexture()));
}
m_renderer->setDevicePixelRatio(m_device_pixel_ratio);
m_renderer->setRootNode(static_cast<QSGRootNode *>(root));
diff --git a/src/quick/scenegraph/qsgdefaultlayer_p.h b/src/quick/scenegraph/qsgdefaultlayer_p.h
index b4a5adab5a..0615045d60 100644
--- a/src/quick/scenegraph/qsgdefaultlayer_p.h
+++ b/src/quick/scenegraph/qsgdefaultlayer_p.h
@@ -60,8 +60,6 @@ public:
QSGNode *item() const { return m_item; }
void setItem(QSGNode *item);
- void setShaderSourceNode(QSGNode *node) { m_shaderSourceNode = node; }
-
QRectF rect() const { return m_rect; }
void setRect(const QRectF &rect);
@@ -100,7 +98,6 @@ private:
void grab();
QSGNode *m_item;
- QSGNode *m_shaderSourceNode;
QRectF m_rect;
QSize m_size;
qreal m_device_pixel_ratio;
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index 0de3c84491..6381c3160f 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -147,19 +147,6 @@ public:
bool eventPending;
};
-bool QSGRenderLoop::useConsistentTiming()
-{
- bool bufferQueuing = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::BufferQueueingOpenGL);
- // Enable fixed animation steps...
- QByteArray fixed = qgetenv("QSG_FIXED_ANIMATION_STEP");
- bool fixedAnimationSteps = bufferQueuing;
- if (fixed == "no")
- fixedAnimationSteps = false;
- else if (fixed.length())
- fixedAnimationSteps = true;
- return fixedAnimationSteps;
-}
-
QSGRenderLoop *QSGRenderLoop::instance()
{
if (!s_instance) {
@@ -170,11 +157,6 @@ QSGRenderLoop *QSGRenderLoop::instance()
s_instance = QSGContext::createWindowManager();
- if (useConsistentTiming()) {
- QUnifiedTimer::instance(true)->setConsistentTiming(true);
- qCDebug(QSG_LOG_INFO, "using fixed animation steps");
- }
-
if (!s_instance) {
enum RenderLoopType {
@@ -283,37 +265,24 @@ void QSGGuiThreadRenderLoop::show(QQuickWindow *window)
void QSGGuiThreadRenderLoop::hide(QQuickWindow *window)
{
- if (!m_windows.contains(window))
- return;
-
- m_windows.remove(window);
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
- if (gl)
- gl->makeCurrent(window);
cd->fireAboutToStop();
- cd->cleanupNodesOnShutdown();
-
- if (m_windows.size() == 0) {
- if (!cd->persistentSceneGraph) {
- rc->invalidate();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- if (!cd->persistentGLContext) {
- delete gl;
- gl = 0;
- }
- }
- }
}
void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window)
{
+ m_windows.remove(window);
hide(window);
+ QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
+ if (gl)
+ gl->makeCurrent(window);
+ d->cleanupNodesOnShutdown();
if (m_windows.size() == 0) {
rc->invalidate();
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
delete gl;
gl = 0;
- } else if (window == gl->surface()) {
+ } else if (gl && window == gl->surface()) {
gl->doneCurrent();
}
}
diff --git a/src/quick/scenegraph/qsgrenderloop_p.h b/src/quick/scenegraph/qsgrenderloop_p.h
index daba3bc69d..e9b58c60ba 100644
--- a/src/quick/scenegraph/qsgrenderloop_p.h
+++ b/src/quick/scenegraph/qsgrenderloop_p.h
@@ -82,8 +82,6 @@ public:
static QSGRenderLoop *instance();
static void setInstance(QSGRenderLoop *instance);
- static bool useConsistentTiming();
-
virtual bool interleaveIncubation() const { return false; }
static void cleanup();
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 92c478b54f..29bee67f69 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -189,9 +189,15 @@ public:
class WMSyncEvent : public WMWindowEvent
{
public:
- WMSyncEvent(QQuickWindow *c, bool inExpose) : WMWindowEvent(c, WM_RequestSync), size(c->size()), syncInExpose(inExpose) { }
+ WMSyncEvent(QQuickWindow *c, bool inExpose, bool force)
+ : WMWindowEvent(c, WM_RequestSync)
+ , size(c->size())
+ , syncInExpose(inExpose)
+ , forceRenderPass(force)
+ {}
QSize size;
bool syncInExpose;
+ bool forceRenderPass;
};
@@ -368,6 +374,10 @@ bool QSGRenderThread::event(QEvent *e)
qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- triggered from expose";
pendingUpdate |= ExposeRequest;
}
+ if (se->forceRenderPass) {
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- repaint regardless";
+ pendingUpdate |= RepaintRequest;
+ }
return true; }
case WM_TryRelease: {
@@ -641,7 +651,6 @@ void QSGRenderThread::run()
qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "run()";
animatorDriver = sgrc->sceneGraphContext()->createAnimationDriver(0);
animatorDriver->install();
- QUnifiedTimer::instance(true)->setConsistentTiming(QSGRenderLoop::useConsistentTiming());
if (QQmlDebugService::isDebuggingEnabled())
QQuickProfiler::registerAnimationCallback();
@@ -855,6 +864,7 @@ void QSGThreadedRenderLoop::handleExposure(QQuickWindow *window)
win.thread = new QSGRenderThread(this, QQuickWindowPrivate::get(window)->context);
win.timerId = 0;
win.updateDuringSync = false;
+ win.forceRenderPass = true; // also covered by polishAndSync(inExpose=true), but doesn't hurt
m_windows << win;
w = &m_windows.last();
}
@@ -998,7 +1008,9 @@ void QSGThreadedRenderLoop::update(QQuickWindow *window)
}
qCDebug(QSG_LOG_RENDERLOOP) << "update on window" << w->window;
- w->thread->postEvent(new QEvent(WM_RequestRepaint));
+ // We set forceRenderPass because we want to make sure the QQuickWindow
+ // actually does a full render pass after the next sync.
+ w->forceRenderPass = true;
maybeUpdate(w);
}
@@ -1107,7 +1119,8 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose)
qCDebug(QSG_LOG_RENDERLOOP) << "- lock for sync";
w->thread->mutex.lock();
m_lockedForSync = true;
- w->thread->postEvent(new WMSyncEvent(window, inExpose));
+ w->thread->postEvent(new WMSyncEvent(window, inExpose, w->forceRenderPass));
+ w->forceRenderPass = false;
qCDebug(QSG_LOG_RENDERLOOP) << "- wait for sync";
if (profileFrames)
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop_p.h b/src/quick/scenegraph/qsgthreadedrenderloop_p.h
index 0e4da27fc6..82f314a6af 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop_p.h
+++ b/src/quick/scenegraph/qsgthreadedrenderloop_p.h
@@ -82,6 +82,7 @@ private:
QSurfaceFormat actualWindowFormat;
int timerId;
uint updateDuringSync : 1;
+ uint forceRenderPass : 1;
};
friend class QSGRenderThread;
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
index b55977296c..11e3376af5 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp
+++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
@@ -189,14 +189,6 @@ void QSGWindowsRenderLoop::show(QQuickWindow *window)
void QSGWindowsRenderLoop::hide(QQuickWindow *window)
{
RLDEBUG("hide");
-
- for (int i=0; i<m_windows.size(); ++i) {
- if (m_windows.at(i).window == window) {
- m_windows.removeAt(i);
- break;
- }
- }
-
// The expose event is queued while hide is sent synchronously, so
// the value might not be updated yet. (plus that the windows plugin
// sends exposed=true when it goes to hidden, so it is doubly broken)
@@ -204,47 +196,41 @@ void QSGWindowsRenderLoop::hide(QQuickWindow *window)
// anyoneShowing will report the right value.
if (window->isExposed())
handleObscurity();
-
if (!m_gl)
return;
-
- QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
- m_gl->makeCurrent(window);
- cd->fireAboutToStop();
- cd->cleanupNodesOnShutdown();
-
- // If this is the last tracked window, check for persistent SG and GL and
- // potentially clean up.
- if (m_windows.size() == 0) {
- if (!cd->persistentSceneGraph) {
- QQuickWindowPrivate::get(window)->context->invalidate();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- if (!cd->persistentGLContext) {
- delete m_gl;
- m_gl = 0;
- }
- }
- }
+ QQuickWindowPrivate::get(window)->fireAboutToStop();
}
void QSGWindowsRenderLoop::windowDestroyed(QQuickWindow *window)
{
RLDEBUG("windowDestroyed");
+ for (int i=0; i<m_windows.size(); ++i) {
+ if (m_windows.at(i).window == window) {
+ m_windows.removeAt(i);
+ break;
+ }
+ }
+
hide(window);
- // If this is the last tracked window, clean up SG and GL.
+ QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
+ if (m_gl)
+ m_gl->makeCurrent(window);
+ d->cleanupNodesOnShutdown();
if (m_windows.size() == 0) {
- QQuickWindowPrivate::get(window)->context->invalidate();
+ d->context->invalidate();
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
delete m_gl;
m_gl = 0;
+ } else if (m_gl) {
+ m_gl->doneCurrent();
}
}
bool QSGWindowsRenderLoop::anyoneShowing() const
{
foreach (const WindowData &wd, m_windows)
- if (wd.window->isExposed() && wd.window->size().isValid())
+ if (wd.window->isVisible() && wd.window->isExposed() && wd.window->size().isValid())
return true;
return false;
}
@@ -255,7 +241,7 @@ void QSGWindowsRenderLoop::exposureChanged(QQuickWindow *window)
if (windowData(window) == 0)
return;
- if (window->isExposed()) {
+ if (window->isExposed() && window->isVisible()) {
// Stop non-visual animation timer as we now have a window rendering
if (m_animationTimer && anyoneShowing()) {
diff --git a/src/quick/scenegraph/shaders/styledtext.vert b/src/quick/scenegraph/shaders/styledtext.vert
index 3ad9497b65..14fefc2564 100644
--- a/src/quick/scenegraph/shaders/styledtext.vert
+++ b/src/quick/scenegraph/shaders/styledtext.vert
@@ -12,5 +12,5 @@ void main()
{
sampleCoord = tCoord * textureScale;
shiftedSampleCoord = (tCoord - shift) * textureScale;
- gl_Position = matrix * vCoord;
-} \ No newline at end of file
+ gl_Position = matrix * floor(vCoord + 0.5);
+}
diff --git a/src/quick/scenegraph/shaders/styledtext_core.vert b/src/quick/scenegraph/shaders/styledtext_core.vert
index b7a3ecc667..65bdb66814 100644
--- a/src/quick/scenegraph/shaders/styledtext_core.vert
+++ b/src/quick/scenegraph/shaders/styledtext_core.vert
@@ -14,5 +14,5 @@ void main()
{
sampleCoord = tCoord * textureScale;
shiftedSampleCoord = (tCoord - shift) * textureScale;
- gl_Position = matrix * vCoord;
-} \ No newline at end of file
+ gl_Position = matrix * round(vCoord);
+}
diff --git a/src/quick/scenegraph/shaders/textmask.vert b/src/quick/scenegraph/shaders/textmask.vert
index 1f45e9cf71..dd8918839e 100644
--- a/src/quick/scenegraph/shaders/textmask.vert
+++ b/src/quick/scenegraph/shaders/textmask.vert
@@ -9,5 +9,5 @@ varying highp vec2 sampleCoord;
void main()
{
sampleCoord = tCoord * textureScale;
- gl_Position = matrix * vCoord;
+ gl_Position = matrix * floor(vCoord + 0.5);
}
diff --git a/src/quick/scenegraph/shaders/textmask_core.vert b/src/quick/scenegraph/shaders/textmask_core.vert
index 619248dccb..d145d33195 100644
--- a/src/quick/scenegraph/shaders/textmask_core.vert
+++ b/src/quick/scenegraph/shaders/textmask_core.vert
@@ -11,5 +11,5 @@ uniform vec2 textureScale;
void main()
{
sampleCoord = tCoord * textureScale;
- gl_Position = matrix * vCoord;
+ gl_Position = matrix * round(vCoord);
}
diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp
index bc091edffe..cb82d721ca 100644
--- a/src/quick/scenegraph/util/qsgatlastexture.cpp
+++ b/src/quick/scenegraph/util/qsgatlastexture.cpp
@@ -307,7 +307,16 @@ void Atlas::uploadBgra(Texture *texture)
funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, r.x() + iw + 1, r.y() + 1, 1, ih, m_externalFormat, GL_UNSIGNED_BYTE, dst);
// Inner part of the image....
- funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, r.x() + 1, r.y() + 1, r.width() - 2, r.height() - 2, m_externalFormat, GL_UNSIGNED_BYTE, src);
+ if (bpl != iw) {
+ int sy = r.y() + 1;
+ int ey = sy + r.height() - 2;
+ for (int y = sy; y < ey; ++y) {
+ funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, r.x() + 1, y, r.width() - 2, 1, m_externalFormat, GL_UNSIGNED_BYTE, src);
+ src += bpl;
+ }
+ } else {
+ funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, r.x() + 1, r.y() + 1, r.width() - 2, r.height() - 2, m_externalFormat, GL_UNSIGNED_BYTE, src);
+ }
}
void Atlas::bind(QSGTexture::Filtering filtering)
diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp
index 3bb0cb0074..673323baa2 100644
--- a/src/quick/scenegraph/util/qsgtexture.cpp
+++ b/src/quick/scenegraph/util/qsgtexture.cpp
@@ -563,7 +563,7 @@ QSGPlainTexture::QSGPlainTexture()
QSGPlainTexture::~QSGPlainTexture()
{
- if (m_texture_id && m_owns_texture)
+ if (m_texture_id && m_owns_texture && QOpenGLContext::currentContext())
QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_texture_id);
}
diff --git a/src/quick/util/qquickanimatorcontroller.cpp b/src/quick/util/qquickanimatorcontroller.cpp
index 01f182c35d..e009de205c 100644
--- a/src/quick/util/qquickanimatorcontroller.cpp
+++ b/src/quick/util/qquickanimatorcontroller.cpp
@@ -184,8 +184,6 @@ void QQuickAnimatorController::beforeNodeSync()
m_nodesAreInvalid = false;
}
-
-
foreach (QQuickAnimatorJob *job, m_activeLeafAnimations) {
if (!job->target())
continue;
@@ -197,9 +195,9 @@ void QQuickAnimatorController::beforeNodeSync()
}
}
foreach (QQuickItem *wiped, m_deletedSinceLastFrame) {
- QQuickTransformAnimatorJob::Helper *helper = m_transforms.value(wiped);
- if (helper)
- helper->item = 0;
+ QQuickTransformAnimatorJob::Helper *helper = m_transforms.take(wiped);
+ // Helper will now already have been reset in all animators referencing it.
+ delete helper;
}
m_deletedSinceLastFrame.clear();
@@ -254,6 +252,7 @@ void QQuickAnimatorController::requestSync()
// These functions are called on the GUI thread.
void QQuickAnimatorController::startJob(QQuickAnimatorProxyJob *proxy, QAbstractAnimationJob *job)
{
+ proxy->markJobManagedByController();
m_starting[job] = proxy;
requestSync();
}
diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp
index 741fa9bb7f..fdbffd4709 100644
--- a/src/quick/util/qquickanimatorjob.cpp
+++ b/src/quick/util/qquickanimatorjob.cpp
@@ -49,6 +49,7 @@ QQuickAnimatorProxyJob::QQuickAnimatorProxyJob(QAbstractAnimationJob *job, QObje
: m_controller(0)
, m_job(job)
, m_internalState(State_Stopped)
+ , m_jobManagedByController(false)
{
m_isRenderThreadProxy = true;
m_animation = qobject_cast<QQuickAbstractAnimation *>(item);
@@ -93,7 +94,10 @@ void QQuickAnimatorProxyJob::deleteJob()
// so delete it through the controller to clean up properly.
if (m_controller)
m_controller->deleteJob(m_job);
- else
+
+ // We explicitly delete the job if the animator controller has never touched
+ // it. If it has, it will have ownership as well.
+ else if (!m_jobManagedByController)
delete m_job;
m_job = 0;
}
@@ -141,11 +145,13 @@ void QQuickAnimatorProxyJob::controllerWasDeleted()
void QQuickAnimatorProxyJob::setWindow(QQuickWindow *window)
{
if (!window) {
- // Stop will trigger syncBackCurrentValues so best to do it before
- // we delete m_job.
stop();
deleteJob();
- return;
+
+ // Upon leaving a window, we reset the controller. This means that
+ // animators will only enter the Starting phase and won't be making
+ // calls to QQuickAnimatorController::startjob().
+ m_controller = 0;
} else if (!m_controller && m_job) {
m_controller = QQuickWindowPrivate::get(window)->animationController;
@@ -250,6 +256,10 @@ QQuickTransformAnimatorJob::QQuickTransformAnimatorJob()
QQuickTransformAnimatorJob::~QQuickTransformAnimatorJob()
{
if (m_helper && --m_helper->ref == 0) {
+ // The only condition for not having a controller is when target was
+ // destroyed, in which case we have neither m_helper nor m_contorller.
+ Q_ASSERT(m_controller);
+ Q_ASSERT(m_helper->item);
m_controller->m_transforms.remove(m_helper->item);
delete m_helper;
}
@@ -260,6 +270,7 @@ void QQuickTransformAnimatorJob::initialize(QQuickAnimatorController *controller
QQuickAnimatorJob::initialize(controller);
if (m_controller) {
+ bool newHelper = m_helper == 0;
m_helper = m_controller->m_transforms.value(m_target);
if (!m_helper) {
m_helper = new Helper();
@@ -267,7 +278,8 @@ void QQuickTransformAnimatorJob::initialize(QQuickAnimatorController *controller
m_controller->m_transforms.insert(m_target, m_helper);
QObject::connect(m_target, SIGNAL(destroyed(QObject*)), m_controller, SLOT(itemDestroyed(QObject*)), Qt::DirectConnection);
} else {
- ++m_helper->ref;
+ if (newHelper) // only add reference the first time around..
+ ++m_helper->ref;
// Make sure leftovers from previous runs are being used...
m_helper->wasSynced = false;
}
@@ -281,6 +293,12 @@ void QQuickTransformAnimatorJob::nodeWasDestroyed()
m_helper->node = 0;
}
+void QQuickTransformAnimatorJob::targetWasDeleted()
+{
+ m_helper = 0;
+ QQuickAnimatorJob::targetWasDeleted();
+}
+
void QQuickTransformAnimatorJob::Helper::sync()
{
const quint32 mask = QQuickItemPrivate::Position
diff --git a/src/quick/util/qquickanimatorjob_p.h b/src/quick/util/qquickanimatorjob_p.h
index 7c6ad823b3..4bdcd6917d 100644
--- a/src/quick/util/qquickanimatorjob_p.h
+++ b/src/quick/util/qquickanimatorjob_p.h
@@ -69,6 +69,7 @@ public:
void startedByController();
void controllerWasDeleted();
+ void markJobManagedByController() { m_jobManagedByController = true; }
protected:
bool event(QEvent *);
@@ -87,7 +88,7 @@ private:
void setWindow(QQuickWindow *window);
static QObject *findAnimationContext(QQuickAbstractAnimation *);
- QQuickAnimatorController *m_controller;
+ QPointer<QQuickAnimatorController> m_controller;
QQuickAbstractAnimation *m_animation;
QAbstractAnimationJob *m_job;
int m_duration;
@@ -100,6 +101,7 @@ private:
};
InternalState m_internalState;
+ bool m_jobManagedByController;
};
class Q_QUICK_PRIVATE_EXPORT QQuickAnimatorJob : public QAbstractAnimationJob
@@ -120,7 +122,7 @@ public:
QEasingCurve easingCurve() const { return m_easing; }
void setEasingCurve(const QEasingCurve &curve) { m_easing = curve; }
- void targetWasDeleted();
+ virtual void targetWasDeleted();
virtual void initialize(QQuickAnimatorController *controller);
virtual void writeBack() = 0;
virtual void nodeWasDestroyed() = 0;
@@ -202,6 +204,7 @@ protected:
QQuickTransformAnimatorJob();
void initialize(QQuickAnimatorController *controller);
void nodeWasDestroyed();
+ void targetWasDeleted() Q_DECL_OVERRIDE;
Helper *m_helper;
};
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index 3e94d0cea6..a2a8ef03c7 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -40,6 +40,7 @@
#include <private/qqmlengine_p.h>
#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qimage_p.h>
#include <qpa/qplatformintegration.h>
#include <QtQuick/private/qsgtexture_p.h>
@@ -70,6 +71,8 @@
#define CACHE_EXPIRE_TIME 30
#define CACHE_REMOVAL_FRACTION 4
+#define PIXMAP_PROFILE(Code) Q_QUICK_PROFILE(QQuickProfiler::ProfilePixmapCache, Code)
+
QT_BEGIN_NAMESPACE
@@ -329,6 +332,29 @@ QNetworkAccessManager *QQuickPixmapReader::networkAccessManager()
return accessManager;
}
+static void maybeRemoveAlpha(QImage *image)
+{
+ // If the image
+ if (image->hasAlphaChannel() && image->data_ptr()
+ && !image->data_ptr()->checkForAlphaPixels()) {
+ switch (image->format()) {
+ case QImage::Format_RGBA8888:
+ case QImage::Format_RGBA8888_Premultiplied:
+ *image = image->convertToFormat(QImage::Format_RGBX8888);
+ break;
+ case QImage::Format_A2BGR30_Premultiplied:
+ *image = image->convertToFormat(QImage::Format_BGR30);
+ break;
+ case QImage::Format_A2RGB30_Premultiplied:
+ *image = image->convertToFormat(QImage::Format_RGB30);
+ break;
+ default:
+ *image = image->convertToFormat(QImage::Format_RGB32);
+ break;
+ }
+ }
+}
+
static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *errorString, QSize *impsize,
const QSize &requestSize)
{
@@ -358,6 +384,7 @@ static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *e
*impsize = imgio.size();
if (imgio.read(image)) {
+ maybeRemoveAlpha(image);
if (impsize && impsize->width() < 0)
*impsize = image->size();
return true;
@@ -500,7 +527,7 @@ void QQuickPixmapReader::processJobs()
replies.remove(reply);
reply->close();
}
- Q_QUICK_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(job->url));
+ PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(job->url));
// deleteLater, since not owned by this thread
job->deleteLater();
}
@@ -512,7 +539,7 @@ void QQuickPixmapReader::processJobs()
runningJob->loading = true;
QUrl url = runningJob->url;
- Q_QUICK_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingStarted>(url));
+ PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingStarted>(url));
QSize requestSize = runningJob->requestSize;
locker.unlock();
@@ -660,7 +687,7 @@ void QQuickPixmapReader::cancel(QQuickPixmapReply *reply)
// If loading was started (reply removed from jobs) but the reply was never processed
// (otherwise it would have deleted itself) we need to profile an error.
if (jobs.removeAll(reply) == 0) {
- Q_QUICK_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(reply->url));
+ PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(reply->url));
}
delete reply;
}
@@ -896,12 +923,12 @@ bool QQuickPixmapReply::event(QEvent *event)
if (data->pixmapStatus == QQuickPixmap::Ready) {
data->textureFactory = de->textureFactory;
data->implicitSize = de->implicitSize;
- Q_QUICK_PROFILE(pixmapLoadingFinished(data->url,
+ PIXMAP_PROFILE(pixmapLoadingFinished(data->url,
data->textureFactory != 0 && data->textureFactory->textureSize().isValid() ?
data->textureFactory->textureSize() :
(data->requestSize.isValid() ? data->requestSize : data->implicitSize)));
} else {
- Q_QUICK_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(data->url));
+ PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(data->url));
data->errorString = de->errorString;
data->removeFromCache(); // We don't continue to cache error'd pixmaps
}
@@ -909,7 +936,7 @@ bool QQuickPixmapReply::event(QEvent *event)
data->reply = 0;
emit finished();
} else {
- Q_QUICK_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(url));
+ PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(url));
}
delete this;
@@ -929,7 +956,7 @@ int QQuickPixmapData::cost() const
void QQuickPixmapData::addref()
{
++refCount;
- Q_QUICK_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapReferenceCountChanged>(url, refCount));
+ PIXMAP_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapReferenceCountChanged>(url, refCount));
if (prevUnreferencedPtr)
pixmapStore()->referencePixmap(this);
}
@@ -938,7 +965,7 @@ void QQuickPixmapData::release()
{
Q_ASSERT(refCount > 0);
--refCount;
- Q_QUICK_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapReferenceCountChanged>(url, refCount));
+ PIXMAP_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapReferenceCountChanged>(url, refCount));
if (refCount == 0) {
if (reply) {
QQuickPixmapReply *cancelReply = reply;
@@ -969,7 +996,7 @@ void QQuickPixmapData::addToCache()
QQuickPixmapKey key = { &url, &requestSize };
pixmapStore()->m_cache.insert(key, this);
inCache = true;
- Q_QUICK_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapCacheCountChanged>(
+ PIXMAP_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapCacheCountChanged>(
url, pixmapStore()->m_cache.count()));
}
}
@@ -980,7 +1007,7 @@ void QQuickPixmapData::removeFromCache()
QQuickPixmapKey key = { &url, &requestSize };
pixmapStore()->m_cache.remove(key);
inCache = false;
- Q_QUICK_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapCacheCountChanged>(
+ PIXMAP_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapCacheCountChanged>(
url, pixmapStore()->m_cache.count()));
}
}
@@ -1259,16 +1286,16 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques
if (!(options & QQuickPixmap::Asynchronous)) {
bool ok = false;
- Q_QUICK_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingStarted>(url));
+ PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingStarted>(url));
d = createPixmapDataSync(this, engine, url, requestSize, &ok);
if (ok) {
- Q_QUICK_PROFILE(pixmapLoadingFinished(url, QSize(width(), height())));
+ PIXMAP_PROFILE(pixmapLoadingFinished(url, QSize(width(), height())));
if (options & QQuickPixmap::Cache)
d->addToCache();
return;
}
if (d) { // loadable, but encountered error while loading
- Q_QUICK_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(url));
+ PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(url));
return;
}
}
diff --git a/src/quick/util/qquickprofiler.cpp b/src/quick/util/qquickprofiler.cpp
index 7cb64bbeeb..c4441ed5dd 100644
--- a/src/quick/util/qquickprofiler.cpp
+++ b/src/quick/util/qquickprofiler.cpp
@@ -40,7 +40,7 @@ QT_BEGIN_NAMESPACE
// instance will be set, unset in constructor. Allows static methods to be inlined.
QQuickProfiler *QQuickProfiler::s_instance = 0;
-bool QQuickProfiler::enabled = false;
+quint64 QQuickProfiler::featuresEnabled = 0;
// convert to QByteArrays that can be sent to the debug client
// use of QDataStream can skew results
@@ -129,7 +129,7 @@ void QQuickProfiler::initialize()
void animationTimerCallback(qint64 delta)
{
- Q_QUICK_PROFILE(animationFrame(delta,
+ Q_QUICK_PROFILE(QQuickProfiler::ProfileAnimations, animationFrame(delta,
QThread::currentThread() == QCoreApplication::instance()->thread() ?
QQuickProfiler::GuiThread : QQuickProfiler::RenderThread));
}
@@ -158,10 +158,10 @@ QQuickProfiler::QQuickProfiler(QQmlProfilerService *service) :
m_timer.start();
// We can always do DirectConnection here as all methods are protected by mutexes
- connect(this, SIGNAL(profilingEnabled()), this, SLOT(startProfilingImpl()),
- Qt::DirectConnection);
- connect(this, SIGNAL(profilingEnabledWhileWaiting()), this, SLOT(startProfilingImpl()),
+ connect(this, SIGNAL(profilingEnabled(quint64)), this, SLOT(startProfilingImpl(quint64)),
Qt::DirectConnection);
+ connect(this, SIGNAL(profilingEnabledWhileWaiting(quint64)),
+ this, SLOT(startProfilingImpl(quint64)), Qt::DirectConnection);
connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)), this, SLOT(setTimer(QElapsedTimer)),
Qt::DirectConnection);
connect(this, SIGNAL(profilingDisabled()), this, SLOT(stopProfilingImpl()),
@@ -179,23 +179,23 @@ QQuickProfiler::QQuickProfiler(QQmlProfilerService *service) :
QQuickProfiler::~QQuickProfiler()
{
QMutexLocker lock(&m_dataMutex);
- enabled = false;
+ featuresEnabled = 0;
s_instance = 0;
}
-void QQuickProfiler::startProfilingImpl()
+void QQuickProfiler::startProfilingImpl(quint64 features)
{
QMutexLocker lock(&m_dataMutex);
next = 0;
m_data.clear();
- enabled = true;
+ featuresEnabled = features;
}
void QQuickProfiler::stopProfilingImpl()
{
{
QMutexLocker lock(&m_dataMutex);
- enabled = false;
+ featuresEnabled = 0;
next = 0;
}
service->dataReady(this);
diff --git a/src/quick/util/qquickprofiler_p.h b/src/quick/util/qquickprofiler_p.h
index 6796fab912..ea37558741 100644
--- a/src/quick/util/qquickprofiler_p.h
+++ b/src/quick/util/qquickprofiler_p.h
@@ -55,40 +55,50 @@
QT_BEGIN_NAMESPACE
-#define Q_QUICK_PROFILE_IF_ENABLED(Code)\
- if (QQuickProfiler::enabled) {\
+#define Q_QUICK_PROFILE_IF_ENABLED(feature, Code)\
+ if (QQuickProfiler::featuresEnabled & (1 << feature)) {\
Code;\
} else\
(void)0
-#define Q_QUICK_PROFILE(Method)\
- Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::Method)
+#define Q_QUICK_PROFILE(feature, Method)\
+ Q_QUICK_PROFILE_IF_ENABLED(feature, QQuickProfiler::Method)
#define Q_QUICK_SG_PROFILE_START(Type)\
- Q_QUICK_PROFILE_IF_ENABLED((QQuickProfiler::startSceneGraphFrame<Type>()))
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::startSceneGraphFrame<Type>()))
#define Q_QUICK_SG_PROFILE_RECORD(Type)\
- Q_QUICK_PROFILE_IF_ENABLED((QQuickProfiler::recordSceneGraphTimestamp<Type>()))
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::recordSceneGraphTimestamp<Type>()))
#define Q_QUICK_SG_PROFILE_SKIP(Type, Skip)\
- Q_QUICK_PROFILE_IF_ENABLED((QQuickProfiler::skipSceneGraphTimestamps<Type, Skip>()))
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::skipSceneGraphTimestamps<Type, Skip>()))
#define Q_QUICK_SG_PROFILE_START_SYNCHRONIZED(Type1, Type2)\
- Q_QUICK_PROFILE_IF_ENABLED((QQuickProfiler::startSceneGraphFrame<Type1, Type2>()))
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::startSceneGraphFrame<Type1, Type2>()))
#define Q_QUICK_SG_PROFILE_SWITCH(Type1, Type2) \
- Q_QUICK_PROFILE_IF_ENABLED((QQuickProfiler::reportSceneGraphFrame<Type1, true, Type2>()))
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::reportSceneGraphFrame<Type1, true, Type2>()))
#define Q_QUICK_SG_PROFILE_REPORT(Type)\
- Q_QUICK_PROFILE_IF_ENABLED((QQuickProfiler::reportSceneGraphFrame<Type, false>()))
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::reportSceneGraphFrame<Type, false>()))
#define Q_QUICK_SG_PROFILE_END(Type)\
- Q_QUICK_PROFILE_IF_ENABLED((QQuickProfiler::reportSceneGraphFrame<Type, true>()))
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::reportSceneGraphFrame<Type, true>()))
#define Q_QUICK_SG_PROFILE_END_WITH_PAYLOAD(Type, Payload)\
- Q_QUICK_PROFILE_IF_ENABLED((QQuickProfiler::reportSceneGraphFrame<Type, true>(Payload)))
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::reportSceneGraphFrame<Type, true>(Payload)))
+#define Q_QUICK_INPUT_PROFILE(Method)\
+ Q_QUICK_PROFILE(QQuickProfiler::ProfileInputEvents, Method)
// This struct is somewhat dangerous to use:
// You can save values either with 32 or 64 bit precision. toByteArrays will
@@ -302,7 +312,11 @@ public:
qint64 sendMessages(qint64 until, QList<QByteArray> &messages);
- static bool enabled;
+ static quint64 featuresEnabled;
+ static bool profilingSceneGraph()
+ {
+ return featuresEnabled & (1 << QQuickProfiler::ProfileSceneGraph);
+ }
static void initialize();
@@ -325,7 +339,7 @@ protected:
}
protected slots:
- void startProfilingImpl();
+ void startProfilingImpl(quint64 features);
void stopProfilingImpl();
void reportDataImpl();
void setTimer(const QElapsedTimer &t);
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index 8d93bf389b..ef6c174b88 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -200,6 +200,26 @@ void QQuickWidgetPrivate::itemGeometryChanged(QQuickItem *resizeItem, const QRec
QQuickItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry);
}
+void QQuickWidgetPrivate::render(bool needsSync)
+{
+ context->makeCurrent(offscreenSurface);
+
+ if (needsSync) {
+ renderControl->polishItems();
+ renderControl->sync();
+ }
+
+ renderControl->render();
+ context->functions()->glFlush();
+
+ if (resolvedFbo) {
+ QRect rect(QPoint(0, 0), fbo->size());
+ QOpenGLFramebufferObject::blitFramebuffer(resolvedFbo, rect, fbo, rect);
+ }
+
+ context->doneCurrent();
+}
+
void QQuickWidgetPrivate::renderSceneGraph()
{
Q_Q(QQuickWidget);
@@ -215,19 +235,8 @@ void QQuickWidgetPrivate::renderSceneGraph()
}
Q_ASSERT(offscreenSurface);
- context->makeCurrent(offscreenSurface);
- renderControl->polishItems();
- renderControl->sync();
- renderControl->render();
- context->functions()->glFlush();
-
- if (resolvedFbo) {
- QRect rect(QPoint(0, 0), fbo->size());
- QOpenGLFramebufferObject::blitFramebuffer(resolvedFbo, rect, fbo, rect);
- }
-
- context->doneCurrent();
- q->update();
+ render(true);
+ q->update(); // schedule composition
}
QImage QQuickWidgetPrivate::grabFramebuffer()
@@ -294,6 +303,11 @@ QImage QQuickWidgetPrivate::grabFramebuffer()
some of the benefits of threaded rendering, for example \l Animator classes and vsync driven
animations, will not be available.
+ \note Avoid calling winId() on a QQuickWidget. This function triggers the creation of
+ a native window, resulting in reduced performance and possibly rendering glitches. The
+ entire purpose of QQuickWidget is to render Quick scenes without a separate native
+ window, hence making it a native widget should always be avoided.
+
\section1 Limitations
Putting other widgets underneath and making the QQuickWidget transparent will not lead
@@ -937,29 +951,14 @@ void QQuickWidget::resizeEvent(QResizeEvent *e)
return;
}
- context->makeCurrent(d->offscreenSurface);
-
- if (needsSync) {
- d->renderControl->polishItems();
- d->renderControl->sync();
- }
-
- d->renderControl->render();
- context->functions()->glFlush();
-
- if (d->resolvedFbo) {
- QRect rect(QPoint(0, 0), d->fbo->size());
- QOpenGLFramebufferObject::blitFramebuffer(d->resolvedFbo, rect, d->fbo, rect);
- }
-
- context->doneCurrent();
+ d->render(needsSync);
}
/*! \reimp */
void QQuickWidget::keyPressEvent(QKeyEvent *e)
{
Q_D(QQuickWidget);
- Q_QUICK_PROFILE(addEvent<QQuickProfiler::Key>());
+ Q_QUICK_INPUT_PROFILE(addEvent<QQuickProfiler::Key>());
QCoreApplication::sendEvent(d->offscreenWindow, e);
}
@@ -968,7 +967,7 @@ void QQuickWidget::keyPressEvent(QKeyEvent *e)
void QQuickWidget::keyReleaseEvent(QKeyEvent *e)
{
Q_D(QQuickWidget);
- Q_QUICK_PROFILE(addEvent<QQuickProfiler::Key>());
+ Q_QUICK_INPUT_PROFILE(addEvent<QQuickProfiler::Key>());
QCoreApplication::sendEvent(d->offscreenWindow, e);
}
@@ -977,7 +976,7 @@ void QQuickWidget::keyReleaseEvent(QKeyEvent *e)
void QQuickWidget::mouseMoveEvent(QMouseEvent *e)
{
Q_D(QQuickWidget);
- Q_QUICK_PROFILE(addEvent<QQuickProfiler::Mouse>());
+ Q_QUICK_INPUT_PROFILE(addEvent<QQuickProfiler::Mouse>());
// Use the constructor taking localPos and screenPos. That puts localPos into the
// event's localPos and windowPos, and screenPos into the event's screenPos. This way
@@ -992,7 +991,7 @@ void QQuickWidget::mouseMoveEvent(QMouseEvent *e)
void QQuickWidget::mouseDoubleClickEvent(QMouseEvent *e)
{
Q_D(QQuickWidget);
- Q_QUICK_PROFILE(addEvent<QQuickProfiler::Mouse>());
+ Q_QUICK_INPUT_PROFILE(addEvent<QQuickProfiler::Mouse>());
// As the second mouse press is suppressed in widget windows we emulate it here for QML.
// See QTBUG-25831
@@ -1025,7 +1024,7 @@ void QQuickWidget::hideEvent(QHideEvent *)
void QQuickWidget::mousePressEvent(QMouseEvent *e)
{
Q_D(QQuickWidget);
- Q_QUICK_PROFILE(addEvent<QQuickProfiler::Mouse>());
+ Q_QUICK_INPUT_PROFILE(addEvent<QQuickProfiler::Mouse>());
QMouseEvent mappedEvent(e->type(), e->localPos(), e->screenPos(), e->button(), e->buttons(), e->modifiers());
QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
@@ -1036,7 +1035,7 @@ void QQuickWidget::mousePressEvent(QMouseEvent *e)
void QQuickWidget::mouseReleaseEvent(QMouseEvent *e)
{
Q_D(QQuickWidget);
- Q_QUICK_PROFILE(addEvent<QQuickProfiler::Mouse>());
+ Q_QUICK_INPUT_PROFILE(addEvent<QQuickProfiler::Mouse>());
QMouseEvent mappedEvent(e->type(), e->localPos(), e->screenPos(), e->button(), e->buttons(), e->modifiers());
QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
@@ -1048,7 +1047,7 @@ void QQuickWidget::mouseReleaseEvent(QMouseEvent *e)
void QQuickWidget::wheelEvent(QWheelEvent *e)
{
Q_D(QQuickWidget);
- Q_QUICK_PROFILE(addEvent<QQuickProfiler::Mouse>());
+ Q_QUICK_INPUT_PROFILE(addEvent<QQuickProfiler::Mouse>());
// Wheel events only have local and global positions, no need to map.
QCoreApplication::sendEvent(d->offscreenWindow, e);
@@ -1099,6 +1098,16 @@ bool QQuickWidget::event(QEvent *e)
case QEvent::WindowChangeInternal:
d->handleWindowChange();
break;
+
+ case QEvent::ScreenChangeInternal:
+ if (d->fbo) {
+ // This will check the size taking the devicePixelRatio into account
+ // and recreate if needed.
+ createFramebufferObject();
+ d->render(true);
+ }
+ break;
+
default:
break;
}
diff --git a/src/quickwidgets/qquickwidget_p.h b/src/quickwidgets/qquickwidget_p.h
index 2289b18d72..2ff9601f77 100644
--- a/src/quickwidgets/qquickwidget_p.h
+++ b/src/quickwidgets/qquickwidget_p.h
@@ -75,6 +75,7 @@ public:
void updateSize();
void updateFrambufferObjectSize();
void setRootObject(QObject *);
+ void render(bool needsSync);
void renderSceneGraph();
void createContext();
void destroyContext();