aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2019-09-05 11:08:59 +0200
committerUlf Hermann <ulf.hermann@qt.io>2019-09-05 11:08:59 +0200
commit2746518c76e02c642ff29faf568de4de90216e58 (patch)
tree822a6d979c13b6450c221b2a45ccfb6674bcb8e4
parent9e32b23a1514f367921b4a9ee25bc864a008463c (diff)
parentbdf0a46c289298f7378796d62ae5fb283e08657d (diff)
Merge remote-tracking branch 'origin/dev' into wip/qt6
Conflicts: .qmake.conf src/qml/qml/qqmlengine.cpp src/qmlmodels/qqmlmodelsmodule.cpp Change-Id: Id60420f8250a9c97fcfe56d4eea19b62c6870404
-rw-r--r--examples/qml/referenceexamples/adding/main.cpp2
-rw-r--r--examples/qml/referenceexamples/adding/person.h2
-rw-r--r--examples/qml/referenceexamples/attached/birthdayparty.cpp2
-rw-r--r--examples/qml/referenceexamples/attached/birthdayparty.h2
-rw-r--r--examples/qml/referenceexamples/attached/main.cpp2
-rw-r--r--examples/qml/referenceexamples/attached/person.h6
-rw-r--r--examples/qml/referenceexamples/binding/birthdayparty.h2
-rw-r--r--examples/qml/referenceexamples/binding/happybirthdaysong.cpp2
-rw-r--r--examples/qml/referenceexamples/binding/happybirthdaysong.h4
-rw-r--r--examples/qml/referenceexamples/binding/main.cpp2
-rw-r--r--examples/qml/referenceexamples/binding/person.h8
-rw-r--r--examples/qml/referenceexamples/coercion/birthdayparty.cpp2
-rw-r--r--examples/qml/referenceexamples/coercion/birthdayparty.h2
-rw-r--r--examples/qml/referenceexamples/coercion/main.cpp2
-rw-r--r--examples/qml/referenceexamples/coercion/person.h6
-rw-r--r--examples/qml/referenceexamples/default/birthdayparty.cpp2
-rw-r--r--examples/qml/referenceexamples/default/birthdayparty.h2
-rw-r--r--examples/qml/referenceexamples/default/main.cpp2
-rw-r--r--examples/qml/referenceexamples/default/person.h6
-rw-r--r--examples/qml/referenceexamples/extended/lineedit.cpp2
-rw-r--r--examples/qml/referenceexamples/extended/main.cpp2
-rw-r--r--examples/qml/referenceexamples/grouped/birthdayparty.cpp2
-rw-r--r--examples/qml/referenceexamples/grouped/birthdayparty.h2
-rw-r--r--examples/qml/referenceexamples/grouped/main.cpp2
-rw-r--r--examples/qml/referenceexamples/grouped/person.h8
-rw-r--r--examples/qml/referenceexamples/methods/birthdayparty.cpp4
-rw-r--r--examples/qml/referenceexamples/methods/birthdayparty.h2
-rw-r--r--examples/qml/referenceexamples/methods/main.cpp2
-rw-r--r--examples/qml/referenceexamples/methods/person.h2
-rw-r--r--examples/qml/referenceexamples/properties/birthdayparty.cpp4
-rw-r--r--examples/qml/referenceexamples/properties/birthdayparty.h2
-rw-r--r--examples/qml/referenceexamples/properties/main.cpp2
-rw-r--r--examples/qml/referenceexamples/properties/person.h2
-rw-r--r--examples/qml/referenceexamples/signal/birthdayparty.cpp2
-rw-r--r--examples/qml/referenceexamples/signal/birthdayparty.h2
-rw-r--r--examples/qml/referenceexamples/signal/main.cpp2
-rw-r--r--examples/qml/referenceexamples/signal/person.h8
-rw-r--r--examples/qml/referenceexamples/valuesource/birthdayparty.cpp2
-rw-r--r--examples/qml/referenceexamples/valuesource/birthdayparty.h2
-rw-r--r--examples/qml/referenceexamples/valuesource/happybirthdaysong.cpp2
-rw-r--r--examples/qml/referenceexamples/valuesource/happybirthdaysong.h4
-rw-r--r--examples/qml/referenceexamples/valuesource/main.cpp2
-rw-r--r--examples/qml/referenceexamples/valuesource/person.h8
-rw-r--r--examples/quick/imageelements/content/multi.icobin0 -> 27110 bytes
-rw-r--r--examples/quick/imageelements/framestepping.qml82
-rw-r--r--examples/quick/imageelements/imageelements.qml2
-rw-r--r--examples/quick/imageelements/imageelements.qrc3
-rw-r--r--examples/quick/imageelements/multiframeborderimage.qml83
-rw-r--r--examples/quick/scenegraph/d3d11underqml/doc/images/d3d11underqml-example.jpgbin0 -> 79343 bytes
-rw-r--r--examples/quick/scenegraph/d3d11underqml/doc/src/d3d11underqml.qdoc58
-rw-r--r--examples/quick/scenegraph/metalunderqml/doc/images/metalunderqml-example.jpgbin0 -> 55194 bytes
-rw-r--r--examples/quick/scenegraph/metalunderqml/doc/src/metalunderqml.qdoc68
-rw-r--r--examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc5
-rw-r--r--examples/quick/scenegraph/rendernode/customrenderitem.cpp48
-rw-r--r--examples/quick/scenegraph/rendernode/d3d12renderer.cpp6
-rw-r--r--examples/quick/scenegraph/rendernode/doc/images/rendernode-example.jpgbin0 -> 77210 bytes
-rw-r--r--examples/quick/scenegraph/rendernode/doc/src/rendernode.qdoc165
-rw-r--r--examples/quick/scenegraph/rendernode/main.cpp2
-rw-r--r--examples/quick/scenegraph/rendernode/main.qml90
-rw-r--r--examples/quick/scenegraph/rendernode/metalrenderer.h100
-rw-r--r--examples/quick/scenegraph/rendernode/metalrenderer.mm326
-rw-r--r--examples/quick/scenegraph/rendernode/metalshader.frag28
-rw-r--r--examples/quick/scenegraph/rendernode/metalshader.vert31
-rw-r--r--examples/quick/scenegraph/rendernode/openglrenderer.cpp31
-rw-r--r--examples/quick/scenegraph/rendernode/openglrenderer.h2
-rw-r--r--examples/quick/scenegraph/rendernode/rendernode.pro6
-rw-r--r--examples/quick/scenegraph/rendernode/rendernode.qrc2
-rw-r--r--examples/quick/shared/CheckBox.qml2
-rw-r--r--examples/quick/shared/LauncherList.qml11
-rw-r--r--examples/quick/shared/Slider.qml2
-rw-r--r--src/imports/builtins/builtins.qmltypes13
-rw-r--r--src/imports/folderlistmodel/plugins.qmltypes2
-rw-r--r--src/imports/labsmodels/plugins.qmltypes373
-rw-r--r--src/imports/layouts/plugins.qmltypes2
-rw-r--r--src/imports/layouts/qquicklinearlayout.cpp4
-rw-r--r--src/imports/localstorage/plugins.qmltypes2
-rw-r--r--src/imports/models/plugins.qmltypes75
-rw-r--r--src/imports/particles/plugins.qmltypes10
-rw-r--r--src/imports/qtqml/dependencies.json2
-rw-r--r--src/imports/qtqml/plugins.qmltypes34
-rw-r--r--src/imports/qtquick2/plugins.qmltypes247
-rw-r--r--src/imports/shapes/plugins.qmltypes10
-rw-r--r--src/imports/statemachine/plugins.qmltypes2
-rw-r--r--src/imports/testlib/main.cpp2
-rw-r--r--src/imports/testlib/plugins.qmltypes8
-rw-r--r--src/imports/wavefrontmesh/plugins.qmltypes2
-rw-r--r--src/imports/window/plugins.qmltypes22
-rw-r--r--src/imports/workerscript/plugins.qmltypes26
-rw-r--r--src/particles/particles.qrc11
-rw-r--r--src/particles/qquickimageparticle.cpp735
-rw-r--r--src/particles/qquickimageparticle_p.h29
-rw-r--r--src/particles/qquickparticlepainter.cpp2
-rw-r--r--src/particles/qquickparticlepainter_p.h1
-rwxr-xr-xsrc/particles/shaders_ng/compile.bat53
-rw-r--r--src/particles/shaders_ng/imageparticle.frag55
-rw-r--r--src/particles/shaders_ng/imageparticle.vert145
-rw-r--r--src/particles/shaders_ng/imageparticle_colored.frag.qsbbin0 -> 1990 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_colored.vert.qsbbin0 -> 3677 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_deformed.frag.qsbbin0 -> 2028 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_deformed.vert.qsbbin0 -> 5044 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_simple.frag.qsbbin0 -> 2000 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_simple.vert.qsbbin0 -> 3639 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_sprite.frag.qsbbin0 -> 2369 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_sprite.vert.qsbbin0 -> 5964 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_tabled.frag.qsbbin0 -> 2240 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_tabled.vert.qsbbin0 -> 5462 bytes
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop.cpp12
-rw-r--r--src/qml/doc/src/qmlfunctions.qdoc10
-rw-r--r--src/qml/parser/qqmljs.g19
-rw-r--r--src/qml/parser/qqmljsast.cpp73
-rw-r--r--src/qml/qml/qml.pri2
-rw-r--r--src/qml/qml/qqml.h10
-rw-r--r--src/qml/qml/qqmlapplicationengine.cpp18
-rw-r--r--src/qml/qml/qqmlapplicationengine.h1
-rw-r--r--src/qml/qml/qqmlapplicationengine_p.h1
-rw-r--r--src/qml/qml/qqmlcomponent.cpp74
-rw-r--r--src/qml/qml/qqmlcomponent.h2
-rw-r--r--src/qml/qml/qqmlcomponent_p.h3
-rw-r--r--src/qml/qml/qqmlengine.cpp24
-rw-r--r--src/qml/qml/qqmlimport.cpp10
-rw-r--r--src/qml/qml/qqmlloggingcategory_p.h2
-rw-r--r--src/qml/qml/qqmlpropertyvalidator.cpp18
-rw-r--r--src/qml/qml/qqmlvaluetype.cpp7
-rw-r--r--src/qml/qml/qqmlvaluetype_p.h4
-rw-r--r--src/qml/types/qqmlbind.cpp2
-rw-r--r--src/qml/types/qqmlconnections.cpp75
-rw-r--r--src/qml/types/qqmlconnections_p.h8
-rw-r--r--src/qmlmodels/configure.json2
-rw-r--r--src/qmlmodels/qqmlmodelsmodule.cpp2
-rw-r--r--src/qmltest/quicktestevent.cpp3
-rw-r--r--src/quick/doc/images/declarative-qtlogo.pngbin3436 -> 1214 bytes
-rw-r--r--src/quick/doc/snippets/cmake-macros/examples.cmake6
-rw-r--r--src/quick/doc/snippets/qml/transitions-list.qml135
-rw-r--r--src/quick/doc/src/cmake-macros.qdoc56
-rw-r--r--src/quick/doc/src/concepts/positioning/righttoleft.qdoc2
-rw-r--r--src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc58
-rw-r--r--src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc312
-rw-r--r--src/quick/doc/src/concepts/visualcanvas/topic.qdoc17
-rw-r--r--src/quick/doc/src/examples.qdoc3
-rw-r--r--src/quick/handlers/qquickdraghandler_p.h4
-rw-r--r--src/quick/handlers/qquicktaphandler.cpp16
-rw-r--r--src/quick/items/qquickanimatedimage.cpp6
-rw-r--r--src/quick/items/qquickanimatedimage_p.h6
-rw-r--r--src/quick/items/qquickborderimage.cpp18
-rw-r--r--src/quick/items/qquickevents.cpp2
-rw-r--r--src/quick/items/qquickflickable.cpp5
-rw-r--r--src/quick/items/qquickframebufferobject.cpp4
-rw-r--r--src/quick/items/qquickframebufferobject.h3
-rw-r--r--src/quick/items/qquickimage.cpp17
-rw-r--r--src/quick/items/qquickimage_p.h8
-rw-r--r--src/quick/items/qquickimagebase.cpp42
-rw-r--r--src/quick/items/qquickimagebase_p.h9
-rw-r--r--src/quick/items/qquickimagebase_p_p.h6
-rw-r--r--src/quick/items/qquickitem.h2
-rw-r--r--src/quick/items/qquickitemsmodule.cpp74
-rw-r--r--src/quick/items/qquickitemview_p.h4
-rw-r--r--src/quick/items/qquicklistview_p.h8
-rw-r--r--src/quick/items/qquickmousearea.cpp2
-rw-r--r--src/quick/items/qquickmousearea_p.h8
-rw-r--r--src/quick/items/qquickpincharea_p.h4
-rw-r--r--src/quick/items/qquickscreen_p.h8
-rw-r--r--src/quick/items/qquickshadereffect_p.h2
-rw-r--r--src/quick/items/qquickshadereffectsource_p.h4
-rw-r--r--src/quick/items/qquicktextinput_p.h8
-rw-r--r--src/quick/items/qquicktextnodeengine.cpp2
-rw-r--r--src/quick/items/qquickview.cpp18
-rw-r--r--src/quick/items/qquickview.h1
-rw-r--r--src/quick/items/qquickview_p.h2
-rw-r--r--src/quick/items/qquickwindow.cpp132
-rw-r--r--src/quick/items/qquickwindow.h10
-rw-r--r--src/quick/items/qquickwindowmodule.cpp8
-rw-r--r--src/quick/items/qquickwindowmodule_p.h4
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp11
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp113
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h2
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendernode.cpp103
-rw-r--r--src/quick/scenegraph/coreapi/qsgtexture.cpp38
-rw-r--r--src/quick/scenegraph/coreapi/qsgtexture.h1
-rw-r--r--src/quick/scenegraph/coreapi/qsgtexture_p.h3
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.cpp4
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp44
-rw-r--r--src/quick/scenegraph/qsgrhisupport.cpp13
-rw-r--r--src/quick/scenegraph/qsgrhisupport_p.h3
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp11
-rw-r--r--src/quick/scenegraph/scenegraph.pri2
-rw-r--r--src/quick/scenegraph/shaders_ng/visualization.vert4
-rw-r--r--src/quick/scenegraph/shaders_ng/visualization.vert.qsbbin2030 -> 2099 bytes
-rw-r--r--src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp4
-rw-r--r--src/quick/scenegraph/util/qsgengine.cpp4
-rw-r--r--src/quick/scenegraph/util/qsgengine.h2
-rw-r--r--src/quick/scenegraph/util/qsgplaintexture.cpp32
-rw-r--r--src/quick/scenegraph/util/qsgplaintexture_p.h4
-rw-r--r--src/quick/scenegraph/util/qsgrhinativetextureimporter.cpp104
-rw-r--r--src/quick/scenegraph/util/qsgrhinativetextureimporter_p.h70
-rw-r--r--src/quick/scenegraph/util/qsgtexturematerial.cpp1
-rw-r--r--src/quick/util/qquickpath.cpp118
-rw-r--r--src/quick/util/qquickpath_p.h16
-rw-r--r--src/quick/util/qquickpixmapcache.cpp81
-rw-r--r--src/quick/util/qquickpixmapcache_p.h5
-rw-r--r--src/quick/util/qquickshortcut_p.h4
-rw-r--r--src/quick/util/qquicktransition.cpp20
-rw-r--r--src/quick/util/qquickutilmodule.cpp6
-rw-r--r--src/quickshapes/qquickshape.cpp2
-rw-r--r--src/src.pro7
-rw-r--r--tests/auto/cmake/CMakeLists.txt12
-rw-r--r--tests/auto/cmake/qmlimportscanner/CMakeLists.txt18
-rw-r--r--tests/auto/cmake/qmlimportscanner/main.cpp53
-rw-r--r--tests/auto/cmake/qmlimportscanner/main.qml5
-rw-r--r--tests/auto/cmake/qmlimportscanner/qis_test.qrc6
-rw-r--r--tests/auto/qml/bindingdependencyapi/dummy_imports.qml8
-rw-r--r--tests/auto/qml/qjsengine/dummy_imports.qml8
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp7
-rw-r--r--tests/auto/qml/qjsvalue/tst_qjsvalue.cpp59
-rw-r--r--tests/auto/qml/qmldiskcache/dummy_imports.qml8
-rw-r--r--tests/auto/qml/qmllint/data/CatchStatement.qml8
-rw-r--r--tests/auto/qml/qmllint/data/catchIdentifierNoWarning.qml7
-rw-r--r--tests/auto/qml/qmllint/qmllint.pro13
-rw-r--r--tests/auto/qml/qmllint/tst_qmllint.cpp (renamed from tests/auto/qml/qmllint/main.cpp)39
-rw-r--r--tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp18
-rw-r--r--tests/auto/qml/qqmlcomponent/data/allJSONTypes.qml9
-rw-r--r--tests/auto/qml/qqmlcomponent/data/variantBasedInitialization.qml21
-rw-r--r--tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp96
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/connection-no-signal-name.qml (renamed from tests/auto/qml/qqmlconnections/data/connection-no-signal-name.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/connection-targetchange.qml (renamed from tests/auto/qml/qqmlconnections/data/connection-targetchange.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-ignored.qml (renamed from tests/auto/qml/qqmlconnections/data/connection-unknownsignals-ignored.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-notarget.qml (renamed from tests/auto/qml/qqmlconnections/data/connection-unknownsignals-notarget.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-parent.qml (renamed from tests/auto/qml/qqmlconnections/data/connection-unknownsignals-parent.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals.qml (renamed from tests/auto/qml/qqmlconnections/data/connection-unknownsignals.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/disabled-at-start.qml (renamed from tests/auto/qml/qqmlconnections/data/disabled-at-start.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/override-proxy-type.qml (renamed from tests/auto/qml/qqmlconnections/data/override-proxy-type.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/rewriteError-global.qml (renamed from tests/auto/qml/qqmlconnections/data/rewriteError-global.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/rewriteError-unnamed.qml (renamed from tests/auto/qml/qqmlconnections/data/rewriteError-unnamed.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/singletontype-target.qml (renamed from tests/auto/qml/qqmlconnections/data/singletontype-target.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/test-connection-implicit.qml (renamed from tests/auto/qml/qqmlconnections/data/test-connection-implicit.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/test-connection.qml (renamed from tests/auto/qml/qqmlconnections/data/test-connection.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/trimming.qml (renamed from tests/auto/qml/qqmlconnections/data/trimming.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/connection-no-signal-name.qml15
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/connection-targetchange.qml25
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-ignored.qml17
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-notarget.qml9
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-parent.qml8
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals.qml11
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/disabled-at-start.qml14
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/override-proxy-type.qml13
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/rewriteError-global.qml8
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/rewriteError-unnamed.qml8
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/singletontype-target.qml22
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/test-connection-implicit.qml9
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/test-connection.qml14
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/trimming.qml13
-rw-r--r--tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp70
-rw-r--r--tests/auto/qml/qqmlecmascript/data/semicolonAfterProperty.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp11
-rw-r--r--tests/auto/qml/qqmllanguage/data/propertyUnknownType.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/propertyUnknownType.qml4
-rw-r--r--tests/auto/qml/qqmllanguage/qqmllanguage.pro2
-rw-r--r--tests/auto/qml/qqmllanguage/qqmllanguage.qrc5
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.cpp1
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.h13
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp116
-rw-r--r--tests/auto/qml/qqmlpropertymap/dummy_imports.qml8
-rw-r--r--tests/auto/qml/qqmlpropertymap/qqmlpropertymap.pro2
-rw-r--r--tests/auto/qml/qqmlsqldatabase/dummy_imports.qml8
-rw-r--r--tests/auto/qml/qqmltimer/dummy_imports.qml9
-rw-r--r--tests/auto/qml/qqmltypeloader/dummy_imports.qml9
-rw-r--r--tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp21
-rw-r--r--tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.pro1
-rw-r--r--tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp16
-rw-r--r--tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp9
-rw-r--r--tests/auto/qml/qv4assembler/tst_qv4assembler.cpp2
-rw-r--r--tests/auto/qml/qv4mm/tst_qv4mm.cpp2
-rw-r--r--tests/auto/quick/qquickborderimage/data/multi.icobin0 -> 27110 bytes
-rw-r--r--tests/auto/quick/qquickborderimage/data/multiframe.qml8
-rw-r--r--tests/auto/quick/qquickborderimage/data/multiframeAsync.qml9
-rw-r--r--tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp65
-rw-r--r--tests/auto/quick/qquickflickable/tst_qquickflickable.cpp15
-rw-r--r--tests/auto/quick/qquickimage/data/multi.icobin0 -> 27110 bytes
-rw-r--r--tests/auto/quick/qquickimage/data/multiframe.qml5
-rw-r--r--tests/auto/quick/qquickimage/data/multiframeAsync.qml6
-rw-r--r--tests/auto/quick/qquickimage/tst_qquickimage.cpp58
-rw-r--r--tests/auto/quick/qquickitem/tst_qquickitem.cpp7
-rw-r--r--tests/auto/quick/qquicklistview/data/addoncompleted.qml3
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp1
-rw-r--r--tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp2
-rw-r--r--tests/auto/quick/qquickshape/data/multiline.pngbin0 -> 1244 bytes
-rw-r--r--tests/auto/quick/qquickshape/data/multiline.qml52
-rw-r--r--tests/auto/quick/qquickshape/data/multilineStronglyTyped.qml59
-rw-r--r--tests/auto/quick/qquickshape/data/polyline.pngbin0 -> 757 bytes
-rw-r--r--tests/auto/quick/qquickshape/data/polyline.qml52
-rw-r--r--tests/auto/quick/qquickshape/tst_qquickshape.cpp334
-rw-r--r--tests/auto/quick/qquicktext/data/verticallyAlignedImageInTable.qml14
-rw-r--r--tests/auto/quick/qquicktext/tst_qquicktext.cpp14
-rw-r--r--tests/auto/quick/qquicktextedit/BLACKLIST2
-rw-r--r--tests/auto/quick/qquickview/tst_qquickview.cpp12
-rw-r--r--tests/auto/shared/testhttpserver.cpp7
-rw-r--r--tests/benchmarks/qml/js/qjsengine/tst_qjsengine.cpp4
-rw-r--r--tests/benchmarks/qml/painting/paintbenchmark.cpp10
-rw-r--r--tests/manual/scenegraph_lancelot/data/text/text_table_vertically_aligned_image.qml14
-rw-r--r--tools/qmlcachegen/generateloader.cpp6
-rw-r--r--tools/qmlcachegen/qmlcachegen.cpp6
-rw-r--r--tools/qmlcachegen/qtquickcompiler.prf10
-rw-r--r--tools/qmlimportscanner/Qt5QmlImportScannerConfig.cmake.in184
-rw-r--r--tools/qmlimportscanner/Qt5QmlImportScannerTemplate.cpp.in5
-rw-r--r--tools/qmlimportscanner/main.cpp46
-rw-r--r--tools/qmlimportscanner/qmlimportscanner.pro45
-rw-r--r--tools/qmllint/findunqualified.cpp14
-rw-r--r--tools/qmllint/findunqualified.h1
-rw-r--r--tools/qmlplugindump/main.cpp133
308 files changed, 6377 insertions, 1127 deletions
diff --git a/examples/qml/referenceexamples/adding/main.cpp b/examples/qml/referenceexamples/adding/main.cpp
index 5c3c891130..e312149da1 100644
--- a/examples/qml/referenceexamples/adding/main.cpp
+++ b/examples/qml/referenceexamples/adding/main.cpp
@@ -62,7 +62,7 @@ int main(int argc, char ** argv)
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:example.qml"));
- Person *person = qobject_cast<Person *>(component.create());
+ auto *person = qobject_cast<Person *>(component.create());
if (person) {
qWarning() << "The person's name is" << person->name();
qWarning() << "They wear a" << person->shoeSize() << "sized shoe";
diff --git a/examples/qml/referenceexamples/adding/person.h b/examples/qml/referenceexamples/adding/person.h
index 44e2ac3b1b..f40c8d8086 100644
--- a/examples/qml/referenceexamples/adding/person.h
+++ b/examples/qml/referenceexamples/adding/person.h
@@ -58,7 +58,7 @@ class Person : public QObject
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize)
public:
- Person(QObject *parent = 0);
+ Person(QObject *parent = nullptr);
QString name() const;
void setName(const QString &);
diff --git a/examples/qml/referenceexamples/attached/birthdayparty.cpp b/examples/qml/referenceexamples/attached/birthdayparty.cpp
index 26aa56e86c..da0cb800fc 100644
--- a/examples/qml/referenceexamples/attached/birthdayparty.cpp
+++ b/examples/qml/referenceexamples/attached/birthdayparty.cpp
@@ -81,7 +81,7 @@ void BirthdayParty::setHost(Person *c)
QQmlListProperty<Person> BirthdayParty::guests()
{
- return QQmlListProperty<Person>(this, m_guests);
+ return {this, m_guests};
}
int BirthdayParty::guestCount() const
diff --git a/examples/qml/referenceexamples/attached/birthdayparty.h b/examples/qml/referenceexamples/attached/birthdayparty.h
index 0684f16255..15375f14d9 100644
--- a/examples/qml/referenceexamples/attached/birthdayparty.h
+++ b/examples/qml/referenceexamples/attached/birthdayparty.h
@@ -76,7 +76,7 @@ class BirthdayParty : public QObject
Q_PROPERTY(QQmlListProperty<Person> guests READ guests)
Q_CLASSINFO("DefaultProperty", "guests")
public:
- BirthdayParty(QObject *parent = 0);
+ BirthdayParty(QObject *parent = nullptr);
Person *host() const;
void setHost(Person *);
diff --git a/examples/qml/referenceexamples/attached/main.cpp b/examples/qml/referenceexamples/attached/main.cpp
index f07f16ae0f..581b033dfc 100644
--- a/examples/qml/referenceexamples/attached/main.cpp
+++ b/examples/qml/referenceexamples/attached/main.cpp
@@ -67,7 +67,7 @@ int main(int argc, char ** argv)
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:example.qml"));
- BirthdayParty *party = qobject_cast<BirthdayParty *>(component.create());
+ auto *party = qobject_cast<BirthdayParty *>(component.create());
if (party && party->host()) {
qWarning() << party->host()->name() << "is having a birthday!";
diff --git a/examples/qml/referenceexamples/attached/person.h b/examples/qml/referenceexamples/attached/person.h
index 9b63773d49..2398da38bf 100644
--- a/examples/qml/referenceexamples/attached/person.h
+++ b/examples/qml/referenceexamples/attached/person.h
@@ -87,7 +87,7 @@ class Person : public QObject
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(ShoeDescription *shoe READ shoe)
public:
- Person(QObject *parent = 0);
+ Person(QObject *parent = nullptr);
QString name() const;
void setName(const QString &);
@@ -102,14 +102,14 @@ class Boy : public Person
{
Q_OBJECT
public:
- Boy(QObject * parent = 0);
+ Boy(QObject * parent = nullptr);
};
class Girl : public Person
{
Q_OBJECT
public:
- Girl(QObject * parent = 0);
+ Girl(QObject * parent = nullptr);
};
#endif // PERSON_H
diff --git a/examples/qml/referenceexamples/binding/birthdayparty.h b/examples/qml/referenceexamples/binding/birthdayparty.h
index 93dad927d7..15e1908ece 100644
--- a/examples/qml/referenceexamples/binding/birthdayparty.h
+++ b/examples/qml/referenceexamples/binding/birthdayparty.h
@@ -83,7 +83,7 @@ class BirthdayParty : public QObject
Q_PROPERTY(QString announcement READ announcement WRITE setAnnouncement)
Q_CLASSINFO("DefaultProperty", "guests")
public:
- BirthdayParty(QObject *parent = 0);
+ BirthdayParty(QObject *parent = nullptr);
Person *host() const;
void setHost(Person *);
diff --git a/examples/qml/referenceexamples/binding/happybirthdaysong.cpp b/examples/qml/referenceexamples/binding/happybirthdaysong.cpp
index fae016091b..5f8e6d696e 100644
--- a/examples/qml/referenceexamples/binding/happybirthdaysong.cpp
+++ b/examples/qml/referenceexamples/binding/happybirthdaysong.cpp
@@ -54,7 +54,7 @@ HappyBirthdaySong::HappyBirthdaySong(QObject *parent)
: QObject(parent), m_line(-1)
{
setName(QString());
- QTimer *timer = new QTimer(this);
+ auto *timer = new QTimer(this);
QObject::connect(timer, &QTimer::timeout, this, &HappyBirthdaySong::advance);
timer->start(1000);
}
diff --git a/examples/qml/referenceexamples/binding/happybirthdaysong.h b/examples/qml/referenceexamples/binding/happybirthdaysong.h
index ab264b80c7..dcfebc06ba 100644
--- a/examples/qml/referenceexamples/binding/happybirthdaysong.h
+++ b/examples/qml/referenceexamples/binding/happybirthdaysong.h
@@ -61,9 +61,9 @@ class HappyBirthdaySong : public QObject, public QQmlPropertyValueSource
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_INTERFACES(QQmlPropertyValueSource)
public:
- HappyBirthdaySong(QObject *parent = 0);
+ HappyBirthdaySong(QObject *parent = nullptr);
- virtual void setTarget(const QQmlProperty &);
+ void setTarget(const QQmlProperty &) override;
QString name() const;
void setName(const QString &);
diff --git a/examples/qml/referenceexamples/binding/main.cpp b/examples/qml/referenceexamples/binding/main.cpp
index cc9ce8f373..99187eba3e 100644
--- a/examples/qml/referenceexamples/binding/main.cpp
+++ b/examples/qml/referenceexamples/binding/main.cpp
@@ -68,7 +68,7 @@ int main(int argc, char ** argv)
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:example.qml"));
- BirthdayParty *party = qobject_cast<BirthdayParty *>(component.create());
+ auto *party = qobject_cast<BirthdayParty *>(component.create());
if (party && party->host()) {
qWarning() << party->host()->name() << "is having a birthday!";
diff --git a/examples/qml/referenceexamples/binding/person.h b/examples/qml/referenceexamples/binding/person.h
index 2cff97a6cd..543b24f971 100644
--- a/examples/qml/referenceexamples/binding/person.h
+++ b/examples/qml/referenceexamples/binding/person.h
@@ -61,7 +61,7 @@ class ShoeDescription : public QObject
Q_PROPERTY(QString brand READ brand WRITE setBrand NOTIFY shoeChanged)
Q_PROPERTY(qreal price READ price WRITE setPrice NOTIFY shoeChanged)
public:
- ShoeDescription(QObject *parent = 0);
+ ShoeDescription(QObject *parent = nullptr);
int size() const;
void setSize(int);
@@ -92,7 +92,7 @@ class Person : public QObject
Q_PROPERTY(ShoeDescription *shoe READ shoe CONSTANT)
// ![0]
public:
- Person(QObject *parent = 0);
+ Person(QObject *parent = nullptr);
QString name() const;
void setName(const QString &);
@@ -110,14 +110,14 @@ class Boy : public Person
{
Q_OBJECT
public:
- Boy(QObject * parent = 0);
+ Boy(QObject * parent = nullptr);
};
class Girl : public Person
{
Q_OBJECT
public:
- Girl(QObject * parent = 0);
+ Girl(QObject * parent = nullptr);
};
#endif // PERSON_H
diff --git a/examples/qml/referenceexamples/coercion/birthdayparty.cpp b/examples/qml/referenceexamples/coercion/birthdayparty.cpp
index e729c42bb5..1bae55076c 100644
--- a/examples/qml/referenceexamples/coercion/birthdayparty.cpp
+++ b/examples/qml/referenceexamples/coercion/birthdayparty.cpp
@@ -66,7 +66,7 @@ void BirthdayParty::setHost(Person *c)
QQmlListProperty<Person> BirthdayParty::guests()
{
- return QQmlListProperty<Person>(this, m_guests);
+ return {this, m_guests};
}
int BirthdayParty::guestCount() const
diff --git a/examples/qml/referenceexamples/coercion/birthdayparty.h b/examples/qml/referenceexamples/coercion/birthdayparty.h
index bb20212ac9..554e7ab0da 100644
--- a/examples/qml/referenceexamples/coercion/birthdayparty.h
+++ b/examples/qml/referenceexamples/coercion/birthdayparty.h
@@ -62,7 +62,7 @@ class BirthdayParty : public QObject
Q_PROPERTY(QQmlListProperty<Person> guests READ guests)
// ![0]
public:
- BirthdayParty(QObject *parent = 0);
+ BirthdayParty(QObject *parent = nullptr);
Person *host() const;
void setHost(Person *);
diff --git a/examples/qml/referenceexamples/coercion/main.cpp b/examples/qml/referenceexamples/coercion/main.cpp
index 04a78b05f7..262cdf6320 100644
--- a/examples/qml/referenceexamples/coercion/main.cpp
+++ b/examples/qml/referenceexamples/coercion/main.cpp
@@ -70,7 +70,7 @@ int main(int argc, char ** argv)
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:example.qml"));
- BirthdayParty *party = qobject_cast<BirthdayParty *>(component.create());
+ auto *party = qobject_cast<BirthdayParty *>(component.create());
if (party && party->host()) {
qWarning() << party->host()->name() << "is having a birthday!";
diff --git a/examples/qml/referenceexamples/coercion/person.h b/examples/qml/referenceexamples/coercion/person.h
index 7169859cce..692cf4eb19 100644
--- a/examples/qml/referenceexamples/coercion/person.h
+++ b/examples/qml/referenceexamples/coercion/person.h
@@ -58,7 +58,7 @@ class Person : public QObject
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize)
public:
- Person(QObject *parent = 0);
+ Person(QObject *parent = nullptr);
QString name() const;
void setName(const QString &);
@@ -76,7 +76,7 @@ class Boy : public Person
{
Q_OBJECT
public:
- Boy(QObject * parent = 0);
+ Boy(QObject * parent = nullptr);
};
//! [girl class]
@@ -84,7 +84,7 @@ class Girl : public Person
{
Q_OBJECT
public:
- Girl(QObject * parent = 0);
+ Girl(QObject * parent = nullptr);
};
//! [girl class]
diff --git a/examples/qml/referenceexamples/default/birthdayparty.cpp b/examples/qml/referenceexamples/default/birthdayparty.cpp
index e729c42bb5..1bae55076c 100644
--- a/examples/qml/referenceexamples/default/birthdayparty.cpp
+++ b/examples/qml/referenceexamples/default/birthdayparty.cpp
@@ -66,7 +66,7 @@ void BirthdayParty::setHost(Person *c)
QQmlListProperty<Person> BirthdayParty::guests()
{
- return QQmlListProperty<Person>(this, m_guests);
+ return {this, m_guests};
}
int BirthdayParty::guestCount() const
diff --git a/examples/qml/referenceexamples/default/birthdayparty.h b/examples/qml/referenceexamples/default/birthdayparty.h
index 6acb395f47..ea63a6a16d 100644
--- a/examples/qml/referenceexamples/default/birthdayparty.h
+++ b/examples/qml/referenceexamples/default/birthdayparty.h
@@ -62,7 +62,7 @@ class BirthdayParty : public QObject
Q_PROPERTY(QQmlListProperty<Person> guests READ guests)
Q_CLASSINFO("DefaultProperty", "guests")
public:
- BirthdayParty(QObject *parent = 0);
+ BirthdayParty(QObject *parent = nullptr);
Person *host() const;
void setHost(Person *);
diff --git a/examples/qml/referenceexamples/default/main.cpp b/examples/qml/referenceexamples/default/main.cpp
index d8c3e466ce..017d6495cd 100644
--- a/examples/qml/referenceexamples/default/main.cpp
+++ b/examples/qml/referenceexamples/default/main.cpp
@@ -65,7 +65,7 @@ int main(int argc, char ** argv)
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:example.qml"));
- BirthdayParty *party = qobject_cast<BirthdayParty *>(component.create());
+ auto *party = qobject_cast<BirthdayParty *>(component.create());
if (party && party->host()) {
qWarning() << party->host()->name() << "is having a birthday!";
diff --git a/examples/qml/referenceexamples/default/person.h b/examples/qml/referenceexamples/default/person.h
index 878c2953e5..87f69276bf 100644
--- a/examples/qml/referenceexamples/default/person.h
+++ b/examples/qml/referenceexamples/default/person.h
@@ -58,7 +58,7 @@ class Person : public QObject
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize)
public:
- Person(QObject *parent = 0);
+ Person(QObject *parent = nullptr);
QString name() const;
void setName(const QString &);
@@ -74,14 +74,14 @@ class Boy : public Person
{
Q_OBJECT
public:
- Boy(QObject * parent = 0);
+ Boy(QObject * parent = nullptr);
};
class Girl : public Person
{
Q_OBJECT
public:
- Girl(QObject * parent = 0);
+ Girl(QObject * parent = nullptr);
};
#endif // PERSON_H
diff --git a/examples/qml/referenceexamples/extended/lineedit.cpp b/examples/qml/referenceexamples/extended/lineedit.cpp
index 777e15db07..feb1a08585 100644
--- a/examples/qml/referenceexamples/extended/lineedit.cpp
+++ b/examples/qml/referenceexamples/extended/lineedit.cpp
@@ -51,7 +51,7 @@
#include <qqml.h>
LineEditExtension::LineEditExtension(QObject *object)
-: QObject(object), m_lineedit(static_cast<QLineEdit *>(object))
+: QObject(object), m_lineedit(qobject_cast<QLineEdit *>(object))
{
}
diff --git a/examples/qml/referenceexamples/extended/main.cpp b/examples/qml/referenceexamples/extended/main.cpp
index c99e052ae5..f91cec76b1 100644
--- a/examples/qml/referenceexamples/extended/main.cpp
+++ b/examples/qml/referenceexamples/extended/main.cpp
@@ -65,7 +65,7 @@ int main(int argc, char ** argv)
// ![1]
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:example.qml"));
- QLineEdit *edit = qobject_cast<QLineEdit *>(component.create());
+ auto *edit = qobject_cast<QLineEdit *>(component.create());
// ![1]
if (edit) {
diff --git a/examples/qml/referenceexamples/grouped/birthdayparty.cpp b/examples/qml/referenceexamples/grouped/birthdayparty.cpp
index e729c42bb5..1bae55076c 100644
--- a/examples/qml/referenceexamples/grouped/birthdayparty.cpp
+++ b/examples/qml/referenceexamples/grouped/birthdayparty.cpp
@@ -66,7 +66,7 @@ void BirthdayParty::setHost(Person *c)
QQmlListProperty<Person> BirthdayParty::guests()
{
- return QQmlListProperty<Person>(this, m_guests);
+ return {this, m_guests};
}
int BirthdayParty::guestCount() const
diff --git a/examples/qml/referenceexamples/grouped/birthdayparty.h b/examples/qml/referenceexamples/grouped/birthdayparty.h
index 7a9a03dabb..edaa11fa88 100644
--- a/examples/qml/referenceexamples/grouped/birthdayparty.h
+++ b/examples/qml/referenceexamples/grouped/birthdayparty.h
@@ -61,7 +61,7 @@ class BirthdayParty : public QObject
Q_PROPERTY(QQmlListProperty<Person> guests READ guests)
Q_CLASSINFO("DefaultProperty", "guests")
public:
- BirthdayParty(QObject *parent = 0);
+ BirthdayParty(QObject *parent = nullptr);
Person *host() const;
void setHost(Person *);
diff --git a/examples/qml/referenceexamples/grouped/main.cpp b/examples/qml/referenceexamples/grouped/main.cpp
index 17dcd09c34..14cd64fe68 100644
--- a/examples/qml/referenceexamples/grouped/main.cpp
+++ b/examples/qml/referenceexamples/grouped/main.cpp
@@ -66,7 +66,7 @@ int main(int argc, char ** argv)
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:example.qml"));
- BirthdayParty *party = qobject_cast<BirthdayParty *>(component.create());
+ auto *party = qobject_cast<BirthdayParty *>(component.create());
if (party && party->host()) {
qWarning() << party->host()->name() << "is having a birthday!";
diff --git a/examples/qml/referenceexamples/grouped/person.h b/examples/qml/referenceexamples/grouped/person.h
index b4e6a894cd..6f6caaee7c 100644
--- a/examples/qml/referenceexamples/grouped/person.h
+++ b/examples/qml/referenceexamples/grouped/person.h
@@ -61,7 +61,7 @@ class ShoeDescription : public QObject
Q_PROPERTY(QString brand READ brand WRITE setBrand)
Q_PROPERTY(qreal price READ price WRITE setPrice)
public:
- ShoeDescription(QObject *parent = 0);
+ ShoeDescription(QObject *parent = nullptr);
int size() const;
void setSize(int);
@@ -89,7 +89,7 @@ class Person : public QObject
Q_PROPERTY(ShoeDescription *shoe READ shoe)
// ![1]
public:
- Person(QObject *parent = 0);
+ Person(QObject *parent = nullptr);
QString name() const;
void setName(const QString &);
@@ -104,14 +104,14 @@ class Boy : public Person
{
Q_OBJECT
public:
- Boy(QObject * parent = 0);
+ Boy(QObject * parent = nullptr);
};
class Girl : public Person
{
Q_OBJECT
public:
- Girl(QObject * parent = 0);
+ Girl(QObject * parent = nullptr);
};
#endif // PERSON_H
diff --git a/examples/qml/referenceexamples/methods/birthdayparty.cpp b/examples/qml/referenceexamples/methods/birthdayparty.cpp
index dfb36257eb..7e750e4f4b 100644
--- a/examples/qml/referenceexamples/methods/birthdayparty.cpp
+++ b/examples/qml/referenceexamples/methods/birthdayparty.cpp
@@ -67,7 +67,7 @@ void BirthdayParty::setHost(Person *c)
QQmlListProperty<Person> BirthdayParty::guests()
{
- return QQmlListProperty<Person>(this, m_guests);
+ return {this, m_guests};
}
int BirthdayParty::guestCount() const
@@ -82,7 +82,7 @@ Person *BirthdayParty::guest(int index) const
void BirthdayParty::invite(const QString &name)
{
- Person *person = new Person(this);
+ auto *person = new Person(this);
person->setName(name);
m_guests.append(person);
}
diff --git a/examples/qml/referenceexamples/methods/birthdayparty.h b/examples/qml/referenceexamples/methods/birthdayparty.h
index 27c164728a..0eb968a841 100644
--- a/examples/qml/referenceexamples/methods/birthdayparty.h
+++ b/examples/qml/referenceexamples/methods/birthdayparty.h
@@ -60,7 +60,7 @@ class BirthdayParty : public QObject
Q_PROPERTY(Person *host READ host WRITE setHost)
Q_PROPERTY(QQmlListProperty<Person> guests READ guests)
public:
- BirthdayParty(QObject *parent = 0);
+ BirthdayParty(QObject *parent = nullptr);
Person *host() const;
void setHost(Person *);
diff --git a/examples/qml/referenceexamples/methods/main.cpp b/examples/qml/referenceexamples/methods/main.cpp
index 974cc26338..89404ec822 100644
--- a/examples/qml/referenceexamples/methods/main.cpp
+++ b/examples/qml/referenceexamples/methods/main.cpp
@@ -63,7 +63,7 @@ int main(int argc, char ** argv)
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:example.qml"));
- BirthdayParty *party = qobject_cast<BirthdayParty *>(component.create());
+ auto *party = qobject_cast<BirthdayParty *>(component.create());
if (party && party->host()) {
qWarning() << party->host()->name() << "is having a birthday!";
diff --git a/examples/qml/referenceexamples/methods/person.h b/examples/qml/referenceexamples/methods/person.h
index 488f8ebac4..749109dc72 100644
--- a/examples/qml/referenceexamples/methods/person.h
+++ b/examples/qml/referenceexamples/methods/person.h
@@ -58,7 +58,7 @@ class Person : public QObject
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize)
public:
- Person(QObject *parent = 0);
+ Person(QObject *parent = nullptr);
QString name() const;
void setName(const QString &);
diff --git a/examples/qml/referenceexamples/properties/birthdayparty.cpp b/examples/qml/referenceexamples/properties/birthdayparty.cpp
index 717c3e0f71..9abb08dbd9 100644
--- a/examples/qml/referenceexamples/properties/birthdayparty.cpp
+++ b/examples/qml/referenceexamples/properties/birthdayparty.cpp
@@ -67,11 +67,11 @@ void BirthdayParty::setHost(Person *c)
QQmlListProperty<Person> BirthdayParty::guests()
{
- return QQmlListProperty<Person>(this, this,
+ return {this, this,
&BirthdayParty::appendGuest,
&BirthdayParty::guestCount,
&BirthdayParty::guest,
- &BirthdayParty::clearGuests);
+ &BirthdayParty::clearGuests};
}
void BirthdayParty::appendGuest(Person* p) {
diff --git a/examples/qml/referenceexamples/properties/birthdayparty.h b/examples/qml/referenceexamples/properties/birthdayparty.h
index 00c5e443b4..8d62c8dcd5 100644
--- a/examples/qml/referenceexamples/properties/birthdayparty.h
+++ b/examples/qml/referenceexamples/properties/birthdayparty.h
@@ -68,7 +68,7 @@ class BirthdayParty : public QObject
// ![2]
// ![3]
public:
- BirthdayParty(QObject *parent = 0);
+ BirthdayParty(QObject *parent = nullptr);
Person *host() const;
void setHost(Person *);
diff --git a/examples/qml/referenceexamples/properties/main.cpp b/examples/qml/referenceexamples/properties/main.cpp
index fbdbd13fd0..a0a2335034 100644
--- a/examples/qml/referenceexamples/properties/main.cpp
+++ b/examples/qml/referenceexamples/properties/main.cpp
@@ -65,7 +65,7 @@ int main(int argc, char ** argv)
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:example.qml"));
- BirthdayParty *party = qobject_cast<BirthdayParty *>(component.create());
+ auto *party = qobject_cast<BirthdayParty *>(component.create());
if (party && party->host()) {
qWarning() << party->host()->name() << "is having a birthday!";
diff --git a/examples/qml/referenceexamples/properties/person.h b/examples/qml/referenceexamples/properties/person.h
index 488f8ebac4..749109dc72 100644
--- a/examples/qml/referenceexamples/properties/person.h
+++ b/examples/qml/referenceexamples/properties/person.h
@@ -58,7 +58,7 @@ class Person : public QObject
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize)
public:
- Person(QObject *parent = 0);
+ Person(QObject *parent = nullptr);
QString name() const;
void setName(const QString &);
diff --git a/examples/qml/referenceexamples/signal/birthdayparty.cpp b/examples/qml/referenceexamples/signal/birthdayparty.cpp
index a5fbb742a5..9d34cdf146 100644
--- a/examples/qml/referenceexamples/signal/birthdayparty.cpp
+++ b/examples/qml/referenceexamples/signal/birthdayparty.cpp
@@ -82,7 +82,7 @@ void BirthdayParty::setHost(Person *c)
QQmlListProperty<Person> BirthdayParty::guests()
{
- return QQmlListProperty<Person>(this, m_guests);
+ return {this, m_guests};
}
int BirthdayParty::guestCount() const
diff --git a/examples/qml/referenceexamples/signal/birthdayparty.h b/examples/qml/referenceexamples/signal/birthdayparty.h
index 759450691e..9aecc8929c 100644
--- a/examples/qml/referenceexamples/signal/birthdayparty.h
+++ b/examples/qml/referenceexamples/signal/birthdayparty.h
@@ -76,7 +76,7 @@ class BirthdayParty : public QObject
Q_PROPERTY(QQmlListProperty<Person> guests READ guests)
Q_CLASSINFO("DefaultProperty", "guests")
public:
- BirthdayParty(QObject *parent = 0);
+ BirthdayParty(QObject *parent = nullptr);
Person *host() const;
void setHost(Person *);
diff --git a/examples/qml/referenceexamples/signal/main.cpp b/examples/qml/referenceexamples/signal/main.cpp
index 7e096edd78..bb75e02bc2 100644
--- a/examples/qml/referenceexamples/signal/main.cpp
+++ b/examples/qml/referenceexamples/signal/main.cpp
@@ -67,7 +67,7 @@ int main(int argc, char ** argv)
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:example.qml"));
- BirthdayParty *party = qobject_cast<BirthdayParty *>(component.create());
+ auto *party = qobject_cast<BirthdayParty *>(component.create());
if (party && party->host()) {
qWarning() << party->host()->name() << "is having a birthday!";
diff --git a/examples/qml/referenceexamples/signal/person.h b/examples/qml/referenceexamples/signal/person.h
index 9b63773d49..06d4f2eb27 100644
--- a/examples/qml/referenceexamples/signal/person.h
+++ b/examples/qml/referenceexamples/signal/person.h
@@ -61,7 +61,7 @@ class ShoeDescription : public QObject
Q_PROPERTY(QString brand READ brand WRITE setBrand)
Q_PROPERTY(qreal price READ price WRITE setPrice)
public:
- ShoeDescription(QObject *parent = 0);
+ ShoeDescription(QObject *parent = nullptr);
int size() const;
void setSize(int);
@@ -87,7 +87,7 @@ class Person : public QObject
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(ShoeDescription *shoe READ shoe)
public:
- Person(QObject *parent = 0);
+ Person(QObject *parent = nullptr);
QString name() const;
void setName(const QString &);
@@ -102,14 +102,14 @@ class Boy : public Person
{
Q_OBJECT
public:
- Boy(QObject * parent = 0);
+ Boy(QObject * parent = nullptr);
};
class Girl : public Person
{
Q_OBJECT
public:
- Girl(QObject * parent = 0);
+ Girl(QObject * parent = nullptr);
};
#endif // PERSON_H
diff --git a/examples/qml/referenceexamples/valuesource/birthdayparty.cpp b/examples/qml/referenceexamples/valuesource/birthdayparty.cpp
index b107c61570..68d5767e8d 100644
--- a/examples/qml/referenceexamples/valuesource/birthdayparty.cpp
+++ b/examples/qml/referenceexamples/valuesource/birthdayparty.cpp
@@ -82,7 +82,7 @@ void BirthdayParty::setHost(Person *c)
QQmlListProperty<Person> BirthdayParty::guests()
{
- return QQmlListProperty<Person>(this, m_guests);
+ return {this, m_guests};
}
int BirthdayParty::guestCount() const
diff --git a/examples/qml/referenceexamples/valuesource/birthdayparty.h b/examples/qml/referenceexamples/valuesource/birthdayparty.h
index f965695cf6..18a9b96147 100644
--- a/examples/qml/referenceexamples/valuesource/birthdayparty.h
+++ b/examples/qml/referenceexamples/valuesource/birthdayparty.h
@@ -80,7 +80,7 @@ class BirthdayParty : public QObject
// ![0]
Q_CLASSINFO("DefaultProperty", "guests")
public:
- BirthdayParty(QObject *parent = 0);
+ BirthdayParty(QObject *parent = nullptr);
Person *host() const;
void setHost(Person *);
diff --git a/examples/qml/referenceexamples/valuesource/happybirthdaysong.cpp b/examples/qml/referenceexamples/valuesource/happybirthdaysong.cpp
index d8e4cad963..da09d3d7ba 100644
--- a/examples/qml/referenceexamples/valuesource/happybirthdaysong.cpp
+++ b/examples/qml/referenceexamples/valuesource/happybirthdaysong.cpp
@@ -54,7 +54,7 @@ HappyBirthdaySong::HappyBirthdaySong(QObject *parent)
: QObject(parent), m_line(-1)
{
setName(QString());
- QTimer *timer = new QTimer(this);
+ auto *timer = new QTimer(this);
QObject::connect(timer, &QTimer::timeout, this, &HappyBirthdaySong::advance);
timer->start(1000);
}
diff --git a/examples/qml/referenceexamples/valuesource/happybirthdaysong.h b/examples/qml/referenceexamples/valuesource/happybirthdaysong.h
index 89bd13c295..e2205a4ebb 100644
--- a/examples/qml/referenceexamples/valuesource/happybirthdaysong.h
+++ b/examples/qml/referenceexamples/valuesource/happybirthdaysong.h
@@ -65,9 +65,9 @@ class HappyBirthdaySong : public QObject, public QQmlPropertyValueSource
Q_PROPERTY(QString name READ name WRITE setName)
// ![1]
public:
- HappyBirthdaySong(QObject *parent = 0);
+ HappyBirthdaySong(QObject *parent = nullptr);
- virtual void setTarget(const QQmlProperty &);
+ void setTarget(const QQmlProperty &) override;
// ![1]
QString name() const;
diff --git a/examples/qml/referenceexamples/valuesource/main.cpp b/examples/qml/referenceexamples/valuesource/main.cpp
index 2f3c466935..4bef695fe2 100644
--- a/examples/qml/referenceexamples/valuesource/main.cpp
+++ b/examples/qml/referenceexamples/valuesource/main.cpp
@@ -69,7 +69,7 @@ int main(int argc, char ** argv)
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:example.qml"));
- BirthdayParty *party = qobject_cast<BirthdayParty *>(component.create());
+ auto *party = qobject_cast<BirthdayParty *>(component.create());
if (party && party->host()) {
qWarning() << party->host()->name() << "is having a birthday!";
diff --git a/examples/qml/referenceexamples/valuesource/person.h b/examples/qml/referenceexamples/valuesource/person.h
index 9b63773d49..06d4f2eb27 100644
--- a/examples/qml/referenceexamples/valuesource/person.h
+++ b/examples/qml/referenceexamples/valuesource/person.h
@@ -61,7 +61,7 @@ class ShoeDescription : public QObject
Q_PROPERTY(QString brand READ brand WRITE setBrand)
Q_PROPERTY(qreal price READ price WRITE setPrice)
public:
- ShoeDescription(QObject *parent = 0);
+ ShoeDescription(QObject *parent = nullptr);
int size() const;
void setSize(int);
@@ -87,7 +87,7 @@ class Person : public QObject
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(ShoeDescription *shoe READ shoe)
public:
- Person(QObject *parent = 0);
+ Person(QObject *parent = nullptr);
QString name() const;
void setName(const QString &);
@@ -102,14 +102,14 @@ class Boy : public Person
{
Q_OBJECT
public:
- Boy(QObject * parent = 0);
+ Boy(QObject * parent = nullptr);
};
class Girl : public Person
{
Q_OBJECT
public:
- Girl(QObject * parent = 0);
+ Girl(QObject * parent = nullptr);
};
#endif // PERSON_H
diff --git a/examples/quick/imageelements/content/multi.ico b/examples/quick/imageelements/content/multi.ico
new file mode 100644
index 0000000000..b748ceaa29
--- /dev/null
+++ b/examples/quick/imageelements/content/multi.ico
Binary files differ
diff --git a/examples/quick/imageelements/framestepping.qml b/examples/quick/imageelements/framestepping.qml
new file mode 100644
index 0000000000..f5bad46e7b
--- /dev/null
+++ b/examples/quick/imageelements/framestepping.qml
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.14
+
+Rectangle {
+ width: 480
+ height: 320
+ Image {
+ id: img
+ anchors.centerIn: parent
+ cache: true
+ source: "content/multi.ico"
+
+ Shortcut {
+ sequence: StandardKey.MoveToNextPage
+ enabled: img.currentFrame < img.frameCount - 1
+ onActivated: img.currentFrame++
+ }
+ Shortcut {
+ sequence: StandardKey.MoveToPreviousPage
+ enabled: img.currentFrame > 0
+ onActivated: img.currentFrame--
+ }
+ }
+
+ Text {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ anchors.margins: 6
+ horizontalAlignment: Text.AlignHCenter
+ text: "frame " + (img.currentFrame + 1) + " of " + img.frameCount +
+ "\nPress PgUp/PgDn to switch frames"
+ }
+}
diff --git a/examples/quick/imageelements/imageelements.qml b/examples/quick/imageelements/imageelements.qml
index dfb4d24ea6..91f2e034f7 100644
--- a/examples/quick/imageelements/imageelements.qml
+++ b/examples/quick/imageelements/imageelements.qml
@@ -64,6 +64,8 @@ Item {
addExample("AnimatedImage", "An image which plays animated formats", Qt.resolvedUrl("animatedimage.qml"));
addExample("AnimatedSprite", "A simple sprite-based animation", Qt.resolvedUrl("animatedsprite.qml"));
addExample("SpriteSequence", "A sprite-based animation with complex transitions", Qt.resolvedUrl("spritesequence.qml"));
+ addExample("FrameStepping", "A multi-frame non-animated image", Qt.resolvedUrl("framestepping.qml"));
+ addExample("MultiBorderImage", "A multi-frame image with scaled borders", Qt.resolvedUrl("multiframeborderimage.qml"));
}
}
}
diff --git a/examples/quick/imageelements/imageelements.qrc b/examples/quick/imageelements/imageelements.qrc
index 2488fb083b..cedef2204c 100644
--- a/examples/quick/imageelements/imageelements.qrc
+++ b/examples/quick/imageelements/imageelements.qrc
@@ -8,6 +8,7 @@
<file>content/colors-stretch.sci</file>
<file>content/colors.png</file>
<file>content/ImageCell.qml</file>
+ <file>content/multi.ico</file>
<file>content/MyBorderImage.qml</file>
<file>content/qt-logo.png</file>
<file>content/shadow.png</file>
@@ -18,6 +19,8 @@
<file>animatedimage.qml</file>
<file>animatedsprite.qml</file>
<file>borderimage.qml</file>
+ <file>framestepping.qml</file>
+ <file>multiframeborderimage.qml</file>
<file>image.qml</file>
<file>shadows.qml</file>
<file>spritesequence.qml</file>
diff --git a/examples/quick/imageelements/multiframeborderimage.qml b/examples/quick/imageelements/multiframeborderimage.qml
new file mode 100644
index 0000000000..0805ea4243
--- /dev/null
+++ b/examples/quick/imageelements/multiframeborderimage.qml
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.14
+
+Rectangle {
+ width: 480
+ height: 320
+ BorderImage {
+ id: img
+ anchors.fill: parent
+ anchors.margins: 6
+ cache: true
+ source: "content/multi.ico"
+ border { left: 19; top: 19; right: 19; bottom: 19 }
+ horizontalTileMode: BorderImage.Stretch
+
+ Shortcut {
+ sequence: StandardKey.MoveToNextPage
+ enabled: img.currentFrame < img.frameCount - 1
+ onActivated: img.currentFrame++
+ }
+ Shortcut {
+ sequence: StandardKey.MoveToPreviousPage
+ enabled: img.currentFrame > 0
+ onActivated: img.currentFrame--
+ }
+ }
+
+ Text {
+ anchors.centerIn: parent
+ horizontalAlignment: Text.AlignHCenter
+ text: "frame " + (img.currentFrame + 1) + " of " + img.frameCount +
+ "\nPress PgUp/PgDn to switch frames"
+ }
+}
diff --git a/examples/quick/scenegraph/d3d11underqml/doc/images/d3d11underqml-example.jpg b/examples/quick/scenegraph/d3d11underqml/doc/images/d3d11underqml-example.jpg
new file mode 100644
index 0000000000..9f1e53ad61
--- /dev/null
+++ b/examples/quick/scenegraph/d3d11underqml/doc/images/d3d11underqml-example.jpg
Binary files differ
diff --git a/examples/quick/scenegraph/d3d11underqml/doc/src/d3d11underqml.qdoc b/examples/quick/scenegraph/d3d11underqml/doc/src/d3d11underqml.qdoc
new file mode 100644
index 0000000000..d7b60d3b81
--- /dev/null
+++ b/examples/quick/scenegraph/d3d11underqml/doc/src/d3d11underqml.qdoc
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example scenegraph/d3d11underqml
+ \title Scene Graph - Direct3D 11 Under QML
+ \ingroup qtquickexamples
+ \brief Shows how to render directly with Direct3D 11 under a Qt Quick scene.
+
+ \image d3d11underqml-example.jpg
+
+ The Direct3D 11 Under QML example shows how an application can make use
+ of the \l QQuickWindow::beforeRendering() signal to draw custom
+ D3D11 content under a Qt Quick scene. This signal is emitted at
+ the start of every frame, before the scene graph starts its
+ rendering, thus any D3D11 draw calls that are made as a response
+ to this signal, will stack under the Qt Quick items.
+
+ As an alternative, applications that wish to render D3D11 content
+ on top of the Qt Quick scene, can do so by connecting to the \l
+ QQuickWindow::afterRendering() signal.
+
+ In this example, we will also see how it is possible to have
+ values that are exposed to QML which affect the D3D11
+ rendering. We animate the threshold value using a NumberAnimation
+ in the QML file and this value is used by the HLSL shader
+ program that draws the squircles.
+
+ The example is equivalent in most ways to the \l{Scene Graph - OpenGL Under
+ QML}{OpenGL Under QML} and \l{Scene Graph - Metal Under QML}{Metal Under
+ QML} examples, they all render the same custom content, just via different
+ native APIs.
+
+ */
diff --git a/examples/quick/scenegraph/metalunderqml/doc/images/metalunderqml-example.jpg b/examples/quick/scenegraph/metalunderqml/doc/images/metalunderqml-example.jpg
new file mode 100644
index 0000000000..98085773de
--- /dev/null
+++ b/examples/quick/scenegraph/metalunderqml/doc/images/metalunderqml-example.jpg
Binary files differ
diff --git a/examples/quick/scenegraph/metalunderqml/doc/src/metalunderqml.qdoc b/examples/quick/scenegraph/metalunderqml/doc/src/metalunderqml.qdoc
new file mode 100644
index 0000000000..d499f47de3
--- /dev/null
+++ b/examples/quick/scenegraph/metalunderqml/doc/src/metalunderqml.qdoc
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example scenegraph/metalunderqml
+ \title Scene Graph - Metal Under QML
+ \ingroup qtquickexamples
+ \brief Shows how to render directly with Metal under a Qt Quick scene.
+
+ \image metalunderqml-example.jpg
+
+ The Metal Under QML example shows how an application can make use
+ of the \l QQuickWindow::beforeRendering() and \l
+ QQuickWindow::beforeRenderPassRecording() signals to draw custom
+ Metal content under a Qt Quick scene. This signal is emitted at
+ the start of every frame, before the scene graph starts its
+ rendering, thus any Metal draw calls that are made as a response
+ to this signal, will stack under the Qt Quick items. There are two
+ signals, because the custom Metal commands are recorded onto the
+ same command buffer with the same render command encoder that the
+ scene graph uses. beforeRendering() on its own is not sufficient
+ for this because it gets emitted at the start of the frame, before
+ having an
+ \l{https://developer.apple.com/documentation/metal/mtlrendercommandencoder}{MTLRenderCommandEncoder}
+ available. By also connecting to beforeRenderPassRecording(), the
+ application can gain access to the necessary native objects.
+
+ As an alternative, applications that wish to render Metal content
+ on top of the Qt Quick scene, can do so by connecting to the \l
+ QQuickWindow::afterRendering() and \l
+ QQuickWindow::afterRenderPassRecording() signals.
+
+ In this example, we will also see how it is possible to have
+ values that are exposed to QML which affect the Metal
+ rendering. We animate the threshold value using a NumberAnimation
+ in the QML file and this value is used by the Metal shader
+ program that draws the squircles.
+
+ The example is equivalent in most ways to the \l{Scene Graph - OpenGL Under
+ QML}{OpenGL Under QML} and \l{Scene Graph - Direct3D 11 Under QML}{Direct3D
+ 11 Under QML} examples, they all render the same custom content, just via
+ different native APIs.
+
+ */
diff --git a/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc b/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc
index 69a9d2ce4b..ed46b40420 100644
--- a/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc
+++ b/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc
@@ -50,6 +50,11 @@
in the QML file and this value is used by the OpenGL shader
program that draws the squircles.
+ The example is equivalent in most ways to the \l{Scene Graph - Direct3D 11 Under
+ QML}{Direct3D 11 Under QML} and \l{Scene Graph - Metal Under QML}{Metal Under
+ QML} examples, they all render the same custom content, just via different
+ native APIs.
+
\snippet scenegraph/openglunderqml/squircle.h 2
First of all, we need an object we can expose to QML. This is a
diff --git a/examples/quick/scenegraph/rendernode/customrenderitem.cpp b/examples/quick/scenegraph/rendernode/customrenderitem.cpp
index 8f248e2ecb..67a9cccfc6 100644
--- a/examples/quick/scenegraph/rendernode/customrenderitem.cpp
+++ b/examples/quick/scenegraph/rendernode/customrenderitem.cpp
@@ -53,16 +53,20 @@
#include <QSGRendererInterface>
#include "openglrenderer.h"
+#include "metalrenderer.h"
#include "d3d12renderer.h"
#include "softwarerenderer.h"
+//! [1]
CustomRenderItem::CustomRenderItem(QQuickItem *parent)
: QQuickItem(parent)
{
// Our item shows something so set the flag.
setFlag(ItemHasContents);
}
+//! [1]
+//! [2]
QSGNode *CustomRenderItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
{
QSGRenderNode *n = static_cast<QSGRenderNode *>(node);
@@ -71,24 +75,46 @@ QSGNode *CustomRenderItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
if (!ri)
return nullptr;
switch (ri->graphicsApi()) {
- case QSGRendererInterface::OpenGL:
+ case QSGRendererInterface::OpenGL:
+ Q_FALLTHROUGH();
+ case QSGRendererInterface::OpenGLRhi:
#if QT_CONFIG(opengl)
- n = new OpenGLRenderNode(this);
- break;
+ n = new OpenGLRenderNode(this);
#endif
- case QSGRendererInterface::Direct3D12:
+ break;
+
+ case QSGRendererInterface::MetalRhi:
+#ifdef Q_OS_DARWIN
+ {
+ MetalRenderNode *metalNode = new MetalRenderNode(this);
+ n = metalNode;
+ metalNode->resourceBuilder()->setWindow(window());
+ QObject::connect(window(), &QQuickWindow::beforeRendering,
+ metalNode->resourceBuilder(), &MetalRenderNodeResourceBuilder::build);
+ }
+#endif
+ break;
+
+ case QSGRendererInterface::Direct3D12: // ### Qt 6: remove
#if QT_CONFIG(d3d12)
- n = new D3D12RenderNode(this);
- break;
+ n = new D3D12RenderNode(this);
#endif
- case QSGRendererInterface::Software:
- n = new SoftwareRenderNode(this);
- break;
+ break;
+
+ case QSGRendererInterface::Software:
+ n = new SoftwareRenderNode(this);
+ break;
- default:
- return nullptr;
+ default:
+ break;
}
+ if (!n)
+ qWarning("QSGRendererInterface reports unknown graphics API %d", ri->graphicsApi());
}
return n;
}
+//! [2]
+
+// This item does not support being moved between windows. If that is desired,
+// itemChange() should be reimplemented as well.
diff --git a/examples/quick/scenegraph/rendernode/d3d12renderer.cpp b/examples/quick/scenegraph/rendernode/d3d12renderer.cpp
index df0e29eb67..878b022950 100644
--- a/examples/quick/scenegraph/rendernode/d3d12renderer.cpp
+++ b/examples/quick/scenegraph/rendernode/d3d12renderer.cpp
@@ -54,6 +54,8 @@
#include <QSGRendererInterface>
#include <QFile>
+// ### Qt 6: remove
+
#if QT_CONFIG(d3d12)
D3D12RenderNode::D3D12RenderNode(QQuickItem *item)
@@ -166,8 +168,8 @@ void D3D12RenderNode::init()
psoDesc.RasterizerState = rastDesc;
psoDesc.BlendState = blendDesc;
// No depth. The correct stacking of the item is ensured by the projection matrix.
- // Do not bother with stencil since we do not apply clipping in the
- // example. If clipping is desired, render() needs to set a different PSO
+ // Note that this does not support clipping.
+ // If clipping is desired, render() needs to set a different PSO
// with stencil enabled whenever the RenderState indicates so.
psoDesc.SampleMask = UINT_MAX;
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
diff --git a/examples/quick/scenegraph/rendernode/doc/images/rendernode-example.jpg b/examples/quick/scenegraph/rendernode/doc/images/rendernode-example.jpg
new file mode 100644
index 0000000000..cbb59b950d
--- /dev/null
+++ b/examples/quick/scenegraph/rendernode/doc/images/rendernode-example.jpg
Binary files differ
diff --git a/examples/quick/scenegraph/rendernode/doc/src/rendernode.qdoc b/examples/quick/scenegraph/rendernode/doc/src/rendernode.qdoc
new file mode 100644
index 0000000000..ba6551fddf
--- /dev/null
+++ b/examples/quick/scenegraph/rendernode/doc/src/rendernode.qdoc
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example scenegraph/rendernode
+ \title Scene Graph - Custom Rendering with QSGRenderNode
+ \ingroup qtquickexamples
+ \brief Shows how to integrate drawing via the native graphics API with the Qt Quick scene graph.
+
+ \image rendernode-example.jpg
+
+ \l QSGRenderNode allows integrating draw and other calls made directly via
+ the Qt Quick scene graph's underlying native graphics API (such as, Vulkan,
+ Metal, Direct 3D, or OpenGL). This example demonstrates implementing a
+ custom QQuickItem backed by a QSGRenderNode implementation, where the node
+ renders a triangle directly via the graphics API. The rest of the scene
+ (background, text, rectangles) are standard Qt Quick items. The example has
+ full support for OpenGL and Metal, as well as the software backend of Qt
+ Quick.
+
+ The custom item behaves like any other Qt Quick item, meaning it
+ participates and stacking and clipping as usual, which is a big difference
+ to the alternative approaches like having the custom rendering as an
+ overlay (connecting to \l QQuickWindow::afterRendering()) and underlay
+ (connecting to \l QQuickWindow::beforeRendering()) because those do not
+ offer the possibility of proper mixing of the custom content with the Qt
+ Quick scene.
+
+ Another important feature is that QSGRenderNode can be helpful to preserve
+ performance, when compared to some of the alternatives. Going through \l
+ QQuickFramebufferObject allows creating a custom item similarly to what
+ this example does, but it does it by rendering the custom content in a
+ texture, and then drawing a textured quad with that texture. This can be
+ expensive on some systems due to the cost of texturing and blending.
+ QSGRenderNode avoids this since the native graphics calls are issued in
+ line with the draw calls for the scene graph's batches.
+
+ All this comes at the cost of being more complex, and not necessarily being
+ suitable for all types of 3D content, in particular where vertices and
+ different depth would clash with the 2D content in the Qt Quick scene
+ graph's batches (those are better served by "flattening" into a 2D texture
+ via approaches like QQuickFramebufferObject). Therefore QSGRenderNode is
+ not always the right choice. It can however a good and powerful choice in
+ many cases. This is what the example demonstrates.
+
+ Let's go through the most important parts of the code:
+
+ \snippet scenegraph/rendernode/main.cpp 1
+
+ Our custom QML type is implemented in the class CustomRenderItem.
+
+ \snippet scenegraph/rendernode/main.qml 2
+
+ The corresponding import in the QML document.
+
+ \snippet scenegraph/rendernode/main.qml 3
+
+ The CustomRenderItem object. It is positioned to fill a big part of the
+ scene, covering its parent (the yellow rectangle; this will be used to
+ demonstrate clipping). The item will have its scale and rotation animated.
+
+ \snippet scenegraph/rendernode/main.qml 4
+
+ Text items are used to show some helpful information, such as, the
+ active graphics API Qt Quick uses.
+
+ \snippet scenegraph/rendernode/main.qml 5
+
+ Clicking the left mouse button is used to toggle clipping on the custom
+ item's parent item. By default this is done using scissoring (GL_SCISSOR_TEST
+ with OpenGL). A well-written QSGRenderNode implementation is expected to be
+ able to take this into account and enable scissor testing when the scene graph
+ indicates that it is necessary.
+
+ The right mouse button is used to toggle an animation on the rotation of
+ the parent item. With clipping enabled, this demonstrates clipping via the
+ stencil buffer since a rectangular scissor is not appropriate when we need
+ to clip to a rotated rectangle shape. The scene graph fills up the stencil
+ buffer as necessary, the QSGRenderNode implementation just has to enable
+ stencil testing using the provided reference value.
+
+ \snippet scenegraph/rendernode/customrenderitem.cpp 1
+
+ Moving on to the CustomRenderItem implementation. This is a visual item.
+
+ \snippet scenegraph/rendernode/customrenderitem.cpp 2
+
+ The implementation of \l QQuickItem::updatePaintNode() creates (if not yet
+ done) and returns an instance of a suitable QSGRenderNode subclass. The
+ example supports multiple graphics APIs, and also the \c software backend.
+
+ Let's look at the the render node for OpenGL (supporting both the
+ traditional, direct OpenGL-based scene graph, and also the modern,
+ abstracted variant using the RHI). For other graphics APIs, the concepts
+ and the outline of a QSGRenderNode implementation are the same. It is worth
+ noting that in some cases it will also be necessary to connect to a signal
+ like \l QQuickWindow::beforeRendering() to perform copy type of operations
+ (such as, vertex buffer uploads). This is not necessary for OpenGL, but it
+ is essential for Vulkan or Metal since there such operations cannot be
+ issued in render() as there is a renderpass being recorded when render() is
+ called.
+
+ \snippet scenegraph/rendernode/openglrenderer.h 1
+
+ The main job is to provide implementations of the virtual QSGRenderNode functions.
+
+ \snippet scenegraph/rendernode/openglrenderer.cpp 1
+
+ The pattern for safe graphics resource management is to do any cleanup in
+ \l{QSGRenderNode::releaseResources()}{releaseResources()}, while also
+ calling this from the destructor.
+
+ \snippet scenegraph/rendernode/openglrenderer.cpp 2
+
+ The render() function initializes graphics resources (in this case, an
+ OpenGL shader program and a vertex buffer), if not yet done. It then
+ makes sure the necessary resources are bound and updates uniforms.
+ The transformation matrix and the opacity are provided by the scene graph
+ either via the \c state argument or base class functions.
+
+ \snippet scenegraph/rendernode/openglrenderer.cpp 5
+
+ This render node is well-behaving since it basically renders in 2D,
+ respecting the item's geometry. This is not mandatory, but then flags() has
+ to return (or not return) the appropriate flags.
+
+ \snippet scenegraph/rendernode/openglrenderer.cpp 3
+
+ After setting up vertex inputs, but before recording a draw call for our
+ triangle, it is important to set some state in order to integrate with the
+ rest of the scene correctly. Setting scissor and stencil as instructed by
+ \c state allows our item to render correctly even when there are one or
+ more clips in the parent chain.
+
+ \snippet scenegraph/rendernode/openglrenderer.cpp 4
+
+ As shown above, we only really render in 2D (no depth), within the item's
+ geometry. changedStates() returns the flags corresponding to the OpenGL
+ states render() touches.
+
+*/
diff --git a/examples/quick/scenegraph/rendernode/main.cpp b/examples/quick/scenegraph/rendernode/main.cpp
index 21419abfc9..146d787e50 100644
--- a/examples/quick/scenegraph/rendernode/main.cpp
+++ b/examples/quick/scenegraph/rendernode/main.cpp
@@ -58,7 +58,9 @@ int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
+//! [1]
qmlRegisterType<CustomRenderItem>("SceneGraphRendering", 2, 0, "CustomRenderItem");
+//! [1]
QQuickView view;
diff --git a/examples/quick/scenegraph/rendernode/main.qml b/examples/quick/scenegraph/rendernode/main.qml
index d0ba4a4669..153a71e097 100644
--- a/examples/quick/scenegraph/rendernode/main.qml
+++ b/examples/quick/scenegraph/rendernode/main.qml
@@ -49,27 +49,65 @@
****************************************************************************/
import QtQuick 2.8
+//! [2]
import SceneGraphRendering 2.0
+//! [2]
Item {
Rectangle {
+ id: bg
anchors.fill: parent
gradient: Gradient {
GradientStop { position: 0; color: "steelblue" }
GradientStop { position: 1; color: "black" }
}
- CustomRenderItem {
- id: renderer
+ //! [5]
+ MouseArea {
anchors.fill: parent
- anchors.margins: 10
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+ onClicked: {
+ if (mouse.button === Qt.LeftButton) {
+ clipper.clip = !clipper.clip
+ } else if (mouse.button === Qt.RightButton) {
+ nonRectClipAnim.running = !nonRectClipAnim.running
+ if (!nonRectClipAnim.running)
+ clipper.rotation = 0;
+ }
+ }
+ }
+ // ![5]
+
+ Rectangle {
+ id: clipper
+ width: parent.width / 2
+ height: parent.height / 2
+ anchors.centerIn: parent
+ border.color: "yellow"
+ border.width: 2
+ color: "transparent"
+ NumberAnimation on rotation {
+ id: nonRectClipAnim
+ from: 0; to: 360; duration: 5000; loops: Animation.Infinite
+ running: false
+ }
+
+ //! [3]
+ CustomRenderItem {
+ id: renderer
+ width: bg.width - 20
+ height: bg.height - 20
+ x: -clipper.x + 10
+ y: -clipper.y + 10
- transform: [
- Rotation { id: rotation; axis.x: 0; axis.z: 0; axis.y: 1; angle: 0; origin.x: renderer.width / 2; origin.y: renderer.height / 2; },
- Translate { id: txOut; x: -renderer.width / 2; y: -renderer.height / 2 },
- Scale { id: scale; },
- Translate { id: txIn; x: renderer.width / 2; y: renderer.height / 2 }
- ]
+ transform: [
+ Rotation { id: rotation; axis.x: 0; axis.z: 0; axis.y: 1; angle: 0; origin.x: renderer.width / 2; origin.y: renderer.height / 2; },
+ Translate { id: txOut; x: -renderer.width / 2; y: -renderer.height / 2 },
+ Scale { id: scale; },
+ Translate { id: txIn; x: renderer.width / 2; y: renderer.height / 2 }
+ ]
+ }
+ //! [3]
}
SequentialAnimation {
@@ -92,19 +130,39 @@ Item {
loops: Animation.Infinite
}
+ //! [4]
Text {
id: label
- anchors.bottom: renderer.bottom
- anchors.left: renderer.left
- anchors.right: renderer.right
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
anchors.margins: 20
+ color: "yellow"
wrapMode: Text.WordWrap
property int api: GraphicsInfo.api
- text: "Custom rendering via the graphics API "
- + (api === GraphicsInfo.OpenGL ? "OpenGL"
- : api === GraphicsInfo.Direct3D12 ? "Direct3D 12"
- : api === GraphicsInfo.Software ? "Software" : "")
+ text: {
+ var apiStr;
+ switch (api) {
+ case GraphicsInfo.OpenGL: apiStr = "OpenGL (direct)"; break;
+ case GraphicsInfo.Direct3D12: apiStr = "Direct3D 12 (direct)"; break;
+ case GraphicsInfo.Software: apiStr = "Software (QPainter)"; break;
+ case GraphicsInfo.OpenGLRhi: apiStr = "OpenGL (RHI)"; break;
+ case GraphicsInfo.MetalRhi: apiStr = "Metal (RHI)"; break;
+ // the example has no other QSGRenderNode subclasses
+ default: apiStr = "<UNSUPPORTED>"; break;
+ }
+ "Custom rendering via the graphics API " + apiStr
+ + "\nLeft click to toggle clipping to yellow rect"
+ + "\nRight click to rotate (can be used to exercise stencil clip instead of scissor)"
+ }
+ // ![4]
+ }
+
+ Text {
+ id: label2
+ anchors.top: parent.top
+ anchors.right: parent.right
color: "yellow"
+ text: "Clip: " + (clipper.clip ? "ON" : "OFF") + " Rotation: " + (nonRectClipAnim.running ? "ON" : "OFF")
}
}
}
diff --git a/examples/quick/scenegraph/rendernode/metalrenderer.h b/examples/quick/scenegraph/rendernode/metalrenderer.h
new file mode 100644
index 0000000000..77c9892313
--- /dev/null
+++ b/examples/quick/scenegraph/rendernode/metalrenderer.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef METALRENDERER_H
+#define METALRENDERER_H
+
+#include <qsgrendernode.h>
+
+#ifdef Q_OS_DARWIN
+
+QT_BEGIN_NAMESPACE
+
+class QQuickItem;
+class QQuickWindow;
+
+QT_END_NAMESPACE
+
+class MetalRenderNodeResourceBuilder : public QObject
+{
+ Q_OBJECT
+
+public:
+ void setWindow(QQuickWindow *w) { m_window = w; }
+
+public slots:
+ void build();
+
+private:
+ QQuickWindow *m_window = nullptr;
+};
+
+class MetalRenderNode : public QSGRenderNode
+{
+public:
+ MetalRenderNode(QQuickItem *item);
+ ~MetalRenderNode();
+
+ void render(const RenderState *state) override;
+ void releaseResources() override;
+ StateFlags changedStates() const override;
+ RenderingFlags flags() const override;
+ QRectF rect() const override;
+
+ MetalRenderNodeResourceBuilder *resourceBuilder() { return &m_resourceBuilder; }
+
+private:
+ QQuickItem *m_item;
+ MetalRenderNodeResourceBuilder m_resourceBuilder;
+};
+
+#endif // Q_OS_DARWIN
+
+#endif
diff --git a/examples/quick/scenegraph/rendernode/metalrenderer.mm b/examples/quick/scenegraph/rendernode/metalrenderer.mm
new file mode 100644
index 0000000000..4cb973abee
--- /dev/null
+++ b/examples/quick/scenegraph/rendernode/metalrenderer.mm
@@ -0,0 +1,326 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "metalrenderer.h"
+#include <QQuickItem>
+#include <QQuickWindow>
+
+#include <Metal/Metal.h>
+
+using FuncAndLib = QPair<id<MTLFunction>, id<MTLLibrary> >;
+
+const int MAX_FRAMES_IN_FLIGHT = 3;
+
+struct {
+ id<MTLDevice> dev = nil;
+ QByteArray vsSource;
+ FuncAndLib vs;
+ QByteArray fsSource;
+ FuncAndLib fs;
+ id<MTLBuffer> vbuf[MAX_FRAMES_IN_FLIGHT];
+ id<MTLBuffer> ubuf[MAX_FRAMES_IN_FLIGHT];
+ id<MTLDepthStencilState> stencilEnabledDsState = nil;
+ id<MTLRenderPipelineState> pipeline = nil;
+} g;
+
+static FuncAndLib compileShaderFromSource(const QByteArray &src, const QByteArray &entryPoint)
+{
+ FuncAndLib fl;
+
+ NSString *srcstr = [NSString stringWithUTF8String: src.constData()];
+ MTLCompileOptions *opts = [[MTLCompileOptions alloc] init];
+ opts.languageVersion = MTLLanguageVersion1_2;
+ NSError *err = nil;
+ fl.second = [g.dev newLibraryWithSource: srcstr options: opts error: &err];
+ [opts release];
+ // srcstr is autoreleased
+
+ if (err) {
+ const QString msg = QString::fromNSString(err.localizedDescription);
+ qFatal("%s", qPrintable(msg));
+ return fl;
+ }
+
+ NSString *name = [NSString stringWithUTF8String: entryPoint.constData()];
+ fl.first = [fl.second newFunctionWithName: name];
+ [name release];
+
+ return fl;
+}
+
+const int VERTEX_SIZE = 6 * sizeof(float);
+
+static float colors[] = {
+ 1.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f
+};
+
+void MetalRenderNodeResourceBuilder::build()
+{
+ if (!g.dev) {
+ QSGRendererInterface *rif = m_window->rendererInterface();
+ Q_ASSERT(rif->graphicsApi() == QSGRendererInterface::MetalRhi);
+
+ g.dev = (id<MTLDevice>) rif->getResource(m_window, QSGRendererInterface::DeviceResource);
+ Q_ASSERT(g.dev);
+ }
+
+ if (g.vsSource.isEmpty()) {
+ const QString filename = QLatin1String(":/scenegraph/rendernode/metalshader.vert");
+ QFile f(filename);
+ if (!f.open(QIODevice::ReadOnly | QIODevice::Text))
+ qFatal("Failed to read shader %s", qPrintable(filename));
+ g.vsSource = f.readAll();
+ g.vs = compileShaderFromSource(g.vsSource, QByteArrayLiteral("main0"));
+ }
+
+ if (g.fsSource.isEmpty()) {
+ const QString filename = QLatin1String(":/scenegraph/rendernode/metalshader.frag");
+ QFile f(filename);
+ if (!f.open(QIODevice::ReadOnly | QIODevice::Text))
+ qFatal("Failed to read shader %s", qPrintable(filename));
+ g.fsSource = f.readAll();
+ g.fs = compileShaderFromSource(g.fsSource, QByteArrayLiteral("main0"));
+ }
+
+ const int framesInFlight = m_window->graphicsStateInfo()->framesInFlight;
+
+ // For simplicity's sake we use shared mode (something like host visible +
+ // host coherent) for everything.
+
+ for (int i = 0; i < framesInFlight; ++i) {
+ // Have multiple versions for vertex too since we'll just memcpy new
+ // vertices based on item width and height on every render(). This could
+ // be optimized further however.
+ if (!g.vbuf[i]) {
+ g.vbuf[i] = [g.dev newBufferWithLength: VERTEX_SIZE + sizeof(colors) options: MTLResourceStorageModeShared];
+ char *p = (char *) [g.vbuf[i] contents];
+ memcpy(p + VERTEX_SIZE, colors, sizeof(colors));
+ }
+
+ if (!g.ubuf[i])
+ g.ubuf[i] = [g.dev newBufferWithLength: 256 options: MTLResourceStorageModeShared];
+ }
+
+ if (!g.stencilEnabledDsState) {
+ MTLDepthStencilDescriptor *dsDesc = [[MTLDepthStencilDescriptor alloc] init];
+ dsDesc.frontFaceStencil = [[MTLStencilDescriptor alloc] init];
+ dsDesc.frontFaceStencil.stencilFailureOperation = MTLStencilOperationKeep;
+ dsDesc.frontFaceStencil.depthFailureOperation = MTLStencilOperationKeep;
+ dsDesc.frontFaceStencil.depthStencilPassOperation = MTLStencilOperationKeep;
+ dsDesc.frontFaceStencil.stencilCompareFunction = MTLCompareFunctionEqual;
+ dsDesc.frontFaceStencil.readMask = 0xFF;
+ dsDesc.frontFaceStencil.writeMask = 0xFF;
+
+ dsDesc.backFaceStencil = [[MTLStencilDescriptor alloc] init];
+ dsDesc.backFaceStencil.stencilFailureOperation = MTLStencilOperationKeep;
+ dsDesc.backFaceStencil.depthFailureOperation = MTLStencilOperationKeep;
+ dsDesc.backFaceStencil.depthStencilPassOperation = MTLStencilOperationKeep;
+ dsDesc.backFaceStencil.stencilCompareFunction = MTLCompareFunctionEqual;
+ dsDesc.backFaceStencil.readMask = 0xFF;
+ dsDesc.backFaceStencil.writeMask = 0xFF;
+
+ g.stencilEnabledDsState = [g.dev newDepthStencilStateWithDescriptor: dsDesc];
+ [dsDesc release];
+ }
+
+ if (!g.pipeline) {
+ MTLVertexDescriptor *inputLayout = [MTLVertexDescriptor vertexDescriptor];
+ inputLayout.attributes[0].format = MTLVertexFormatFloat2;
+ inputLayout.attributes[0].offset = 0;
+ inputLayout.attributes[0].bufferIndex = 1; // ubuf is 0, vbuf is 1 and 2
+ inputLayout.attributes[1].format = MTLVertexFormatFloat3;
+ inputLayout.attributes[1].offset = 0;
+ inputLayout.attributes[1].bufferIndex = 2;
+ inputLayout.layouts[1].stride = 2 * sizeof(float);
+ inputLayout.layouts[2].stride = 3 * sizeof(float);
+
+ MTLRenderPipelineDescriptor *rpDesc = [[MTLRenderPipelineDescriptor alloc] init];
+ rpDesc.vertexDescriptor = inputLayout;
+
+ rpDesc.vertexFunction = g.vs.first;
+ rpDesc.fragmentFunction = g.fs.first;
+
+ rpDesc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
+ rpDesc.colorAttachments[0].blendingEnabled = true;
+ rpDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorOne;
+ rpDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
+ rpDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
+ rpDesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
+
+ if (g.dev.depth24Stencil8PixelFormatSupported) {
+ rpDesc.depthAttachmentPixelFormat = MTLPixelFormatDepth24Unorm_Stencil8;
+ rpDesc.stencilAttachmentPixelFormat = MTLPixelFormatDepth24Unorm_Stencil8;
+ } else {
+ rpDesc.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
+ rpDesc.stencilAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
+ }
+
+ NSError *err = nil;
+ g.pipeline = [g.dev newRenderPipelineStateWithDescriptor: rpDesc error: &err];
+ if (!g.pipeline) {
+ const QString msg = QString::fromNSString(err.localizedDescription);
+ qFatal("Failed to create render pipeline state: %s", qPrintable(msg));
+ }
+ [rpDesc release];
+ }
+}
+
+MetalRenderNode::MetalRenderNode(QQuickItem *item)
+ : m_item(item)
+{
+ g.vs.first = g.fs.first = nil;
+ g.vs.second = g.fs.second = nil;
+
+ for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
+ g.vbuf[i] = nil;
+ g.ubuf[i] = nil;
+ }
+}
+
+MetalRenderNode::~MetalRenderNode()
+{
+ releaseResources();
+}
+
+void MetalRenderNode::releaseResources()
+{
+ [g.stencilEnabledDsState release];
+ g.stencilEnabledDsState = nil;
+
+ [g.pipeline release];
+ g.pipeline = nil;
+
+ [g.vs.first release];
+ [g.vs.second release];
+
+ [g.fs.first release];
+ [g.fs.second release];
+
+ g.vs.first = g.fs.first = nil;
+ g.vs.second = g.fs.second = nil;
+
+ for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
+ [g.vbuf[i] release];
+ g.vbuf[i] = nil;
+ [g.ubuf[i] release];
+ g.ubuf[i] = nil;
+ }
+}
+
+void MetalRenderNode::render(const RenderState *state)
+{
+ QQuickWindow *window = m_item->window();
+ const QQuickWindow::GraphicsStateInfo *stateInfo = window->graphicsStateInfo();
+ id<MTLBuffer> vbuf = g.vbuf[stateInfo->currentFrameSlot];
+ id<MTLBuffer> ubuf = g.ubuf[stateInfo->currentFrameSlot];
+
+ QPointF p0(m_item->width() - 1, m_item->height() - 1);
+ QPointF p1(0, 0);
+ QPointF p2(0, m_item->height() - 1);
+
+ float vertices[6] = { float(p0.x()), float(p0.y()),
+ float(p1.x()), float(p1.y()),
+ float(p2.x()), float(p2.y()) };
+ char *p = (char *) [vbuf contents];
+ memcpy(p, vertices, VERTEX_SIZE);
+
+ const QMatrix4x4 mvp = *state->projectionMatrix() * *matrix();
+ const float opacity = inheritedOpacity();
+
+ p = (char *) [ubuf contents];
+ memcpy(p, mvp.constData(), 64);
+ memcpy(p + 64, &opacity, 4);
+
+ QSGRendererInterface *rif = window->rendererInterface();
+ id<MTLRenderCommandEncoder> encoder = (id<MTLRenderCommandEncoder>) rif->getResource(
+ window, QSGRendererInterface::CommandEncoderResource);
+ Q_ASSERT(encoder);
+
+ [encoder setVertexBuffer: vbuf offset: 0 atIndex: 1];
+ [encoder setVertexBuffer: vbuf offset: VERTEX_SIZE atIndex: 2];
+
+ [encoder setVertexBuffer: ubuf offset: 0 atIndex: 0];
+ [encoder setFragmentBuffer: ubuf offset: 0 atIndex: 0];
+
+ // Clip support.
+ if (state->scissorEnabled()) {
+ const QRect r = state->scissorRect(); // bottom-up
+ MTLScissorRect s;
+ s.x = r.x();
+ s.y = (window->height() * window->effectiveDevicePixelRatio()) - (r.y() + r.height());
+ s.width = r.width();
+ s.height = r.height();
+ [encoder setScissorRect: s];
+ }
+ if (state->stencilEnabled()) {
+ [encoder setDepthStencilState: g.stencilEnabledDsState];
+ [encoder setStencilReferenceValue: state->stencilValue()];
+ }
+
+ [encoder setRenderPipelineState: g.pipeline];
+ [encoder drawPrimitives: MTLPrimitiveTypeTriangle vertexStart: 0 vertexCount: 3 instanceCount: 1 baseInstance: 0];
+}
+
+QSGRenderNode::StateFlags MetalRenderNode::changedStates() const
+{
+ return BlendState | ScissorState | StencilState;
+}
+
+QSGRenderNode::RenderingFlags MetalRenderNode::flags() const
+{
+ return BoundedRectRendering | DepthAwareRendering;
+}
+
+QRectF MetalRenderNode::rect() const
+{
+ return QRect(0, 0, m_item->width(), m_item->height());
+}
diff --git a/examples/quick/scenegraph/rendernode/metalshader.frag b/examples/quick/scenegraph/rendernode/metalshader.frag
new file mode 100644
index 0000000000..907faa537f
--- /dev/null
+++ b/examples/quick/scenegraph/rendernode/metalshader.frag
@@ -0,0 +1,28 @@
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+struct buf
+{
+ float4x4 matrix;
+ float opacity;
+};
+
+struct main0_out
+{
+ float4 fragColor [[color(0)]];
+};
+
+struct main0_in
+{
+ float4 v_color [[user(locn0)]];
+};
+
+fragment main0_out main0(main0_in in [[stage_in]], constant buf& ubuf [[buffer(0)]])
+{
+ main0_out out = {};
+ out.fragColor = in.v_color * ubuf.opacity;
+ return out;
+}
+
diff --git a/examples/quick/scenegraph/rendernode/metalshader.vert b/examples/quick/scenegraph/rendernode/metalshader.vert
new file mode 100644
index 0000000000..12b721f524
--- /dev/null
+++ b/examples/quick/scenegraph/rendernode/metalshader.vert
@@ -0,0 +1,31 @@
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+struct buf
+{
+ float4x4 matrix;
+ float opacity;
+};
+
+struct main0_out
+{
+ float4 v_color [[user(locn0)]];
+ float4 gl_Position [[position]];
+};
+
+struct main0_in
+{
+ float4 pos [[attribute(0)]];
+ float4 color [[attribute(1)]];
+};
+
+vertex main0_out main0(main0_in in [[stage_in]], constant buf& ubuf [[buffer(0)]])
+{
+ main0_out out = {};
+ out.v_color = in.color;
+ out.gl_Position = ubuf.matrix * in.pos;
+ return out;
+}
+
diff --git a/examples/quick/scenegraph/rendernode/openglrenderer.cpp b/examples/quick/scenegraph/rendernode/openglrenderer.cpp
index 3c68830db6..0633731617 100644
--- a/examples/quick/scenegraph/rendernode/openglrenderer.cpp
+++ b/examples/quick/scenegraph/rendernode/openglrenderer.cpp
@@ -57,6 +57,7 @@
#include <QOpenGLBuffer>
#include <QOpenGLFunctions>
+//! [1]
OpenGLRenderNode::OpenGLRenderNode(QQuickItem *item)
: m_item(item)
{
@@ -74,6 +75,7 @@ void OpenGLRenderNode::releaseResources()
delete m_vbo;
m_vbo = nullptr;
}
+//! [1]
void OpenGLRenderNode::init()
{
@@ -121,19 +123,21 @@ void OpenGLRenderNode::init()
m_vbo->release();
}
+//! [2]
void OpenGLRenderNode::render(const RenderState *state)
{
if (!m_program)
init();
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
-
m_program->bind();
m_program->setUniformValue(m_matrixUniform, *state->projectionMatrix() * *matrix());
m_program->setUniformValue(m_opacityUniform, float(inheritedOpacity()));
+//! [2]
m_vbo->bind();
+//! [5]
QPointF p0(m_item->width() - 1, m_item->height() - 1);
QPointF p1(0, 0);
QPointF p2(0, m_item->height() - 1);
@@ -142,23 +146,43 @@ void OpenGLRenderNode::render(const RenderState *state)
GLfloat(p1.x()), GLfloat(p1.y()),
GLfloat(p2.x()), GLfloat(p2.y()) };
m_vbo->write(0, vertices, sizeof(vertices));
+//! [5]
m_program->setAttributeBuffer(0, GL_FLOAT, 0, 2);
m_program->setAttributeBuffer(1, GL_FLOAT, sizeof(vertices), 3);
m_program->enableAttributeArray(0);
m_program->enableAttributeArray(1);
- // Note that clipping (scissor or stencil) is ignored in this example.
+ // We are prepared both for the legacy (direct OpenGL) and the modern
+ // (abstracted by RHI) OpenGL scenegraph. So set all the states that are
+ // important to us.
+
+ //! [3]
+ f->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
f->glEnable(GL_BLEND);
f->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ // Clip support.
+ if (state->scissorEnabled()) {
+ f->glEnable(GL_SCISSOR_TEST);
+ const QRect r = state->scissorRect(); // already bottom-up
+ f->glScissor(r.x(), r.y(), r.width(), r.height());
+ }
+ if (state->stencilEnabled()) {
+ f->glEnable(GL_STENCIL_TEST);
+ f->glStencilFunc(GL_EQUAL, state->stencilValue(), 0xFF);
+ f->glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ }
+
f->glDrawArrays(GL_TRIANGLES, 0, 3);
+ //! [3]
}
+//! [4]
QSGRenderNode::StateFlags OpenGLRenderNode::changedStates() const
{
- return BlendState;
+ return BlendState | ScissorState | StencilState;
}
QSGRenderNode::RenderingFlags OpenGLRenderNode::flags() const
@@ -170,5 +194,6 @@ QRectF OpenGLRenderNode::rect() const
{
return QRect(0, 0, m_item->width(), m_item->height());
}
+//! [4]
#endif // opengl
diff --git a/examples/quick/scenegraph/rendernode/openglrenderer.h b/examples/quick/scenegraph/rendernode/openglrenderer.h
index ac640405c5..8d2d3caad1 100644
--- a/examples/quick/scenegraph/rendernode/openglrenderer.h
+++ b/examples/quick/scenegraph/rendernode/openglrenderer.h
@@ -63,6 +63,7 @@ class QOpenGLBuffer;
QT_END_NAMESPACE
+//! [1]
class OpenGLRenderNode : public QSGRenderNode
{
public:
@@ -74,6 +75,7 @@ public:
StateFlags changedStates() const override;
RenderingFlags flags() const override;
QRectF rect() const override;
+//! [1]
private:
void init();
diff --git a/examples/quick/scenegraph/rendernode/rendernode.pro b/examples/quick/scenegraph/rendernode/rendernode.pro
index 76e498042b..897b0b1f08 100644
--- a/examples/quick/scenegraph/rendernode/rendernode.pro
+++ b/examples/quick/scenegraph/rendernode/rendernode.pro
@@ -22,3 +22,9 @@ qtConfig(d3d12) {
SOURCES += d3d12renderer.cpp
LIBS += -ld3d12
}
+
+macos {
+ HEADERS += metalrenderer.h
+ SOURCES += metalrenderer.mm
+ LIBS += -framework Metal -framework AppKit
+}
diff --git a/examples/quick/scenegraph/rendernode/rendernode.qrc b/examples/quick/scenegraph/rendernode/rendernode.qrc
index 049adcf8a6..5907eab62c 100644
--- a/examples/quick/scenegraph/rendernode/rendernode.qrc
+++ b/examples/quick/scenegraph/rendernode/rendernode.qrc
@@ -3,5 +3,7 @@
<file>main.qml</file>
<file>shader_vert.cso</file>
<file>shader_frag.cso</file>
+ <file>metalshader.vert</file>
+ <file>metalshader.frag</file>
</qresource>
</RCC>
diff --git a/examples/quick/shared/CheckBox.qml b/examples/quick/shared/CheckBox.qml
index 7b1588d2d9..51b6aabc09 100644
--- a/examples/quick/shared/CheckBox.qml
+++ b/examples/quick/shared/CheckBox.qml
@@ -87,7 +87,7 @@ Item {
anchors.margins: frame.width / 5
fillMode: Image.PreserveAspectFit
smooth: true
- visible: checked
+ visible: root.checked
}
}
Text {
diff --git a/examples/quick/shared/LauncherList.qml b/examples/quick/shared/LauncherList.qml
index fe44cf3634..9859b5b635 100644
--- a/examples/quick/shared/LauncherList.qml
+++ b/examples/quick/shared/LauncherList.qml
@@ -51,6 +51,7 @@
import QtQuick 2.12
Rectangle {
+ id: root
property int activePageCount: 0
//model is a list of {"name":"somename", "url":"file:///some/url/mainfile.qml"}
@@ -74,7 +75,7 @@ Rectangle {
id: launcherList
clip: true
delegate: SimpleLauncherDelegate{
- onClicked: showExample(url)
+ onClicked: root.showExample(url)
}
model: ListModel {id:myModel}
anchors.fill: parent
@@ -116,7 +117,7 @@ Rectangle {
ParallelAnimation {
id: showAnim
ScriptAction {
- script: activePageCount++
+ script: root.activePageCount++
}
NumberAnimation {
target: launcherList
@@ -144,7 +145,7 @@ Rectangle {
id: exitAnim
ScriptAction {
- script: activePageCount--
+ script: root.activePageCount--
}
ParallelAnimation {
@@ -182,7 +183,7 @@ Rectangle {
visible: height > 0
anchors.bottom: parent.bottom
width: parent.width
- height: activePageCount > 0 ? 40 : 0
+ height: root.activePageCount > 0 ? 40 : 0
Behavior on height {
NumberAnimation {
@@ -222,7 +223,7 @@ Rectangle {
TapHandler {
id: tapHandler
- enabled: activePageCount > 0
+ enabled: root.activePageCount > 0
onTapped: {
pageContainer.children[pageContainer.children.length - 1].exit()
}
diff --git a/examples/quick/shared/Slider.qml b/examples/quick/shared/Slider.qml
index cdda86e39e..5b08034571 100644
--- a/examples/quick/shared/Slider.qml
+++ b/examples/quick/shared/Slider.qml
@@ -83,7 +83,7 @@ Item {
anchors.left: parent.left
anchors.leftMargin: 16
height: childrenRect.height
- width: Math.max(minLabelWidth, childrenRect.width)
+ width: Math.max(slider.minLabelWidth, childrenRect.width)
anchors.verticalCenter: parent.verticalCenter
Text {
text: slider.name + ":"
diff --git a/src/imports/builtins/builtins.qmltypes b/src/imports/builtins/builtins.qmltypes
index 4ad103f8de..c783c63caf 100644
--- a/src/imports/builtins/builtins.qmltypes
+++ b/src/imports/builtins/builtins.qmltypes
@@ -131,6 +131,13 @@ Module {
}
}
Enum {
+ name: "SplitBehavior"
+ values: {
+ "KeepEmptyParts": 0,
+ "SkipEmptyParts": 1
+ }
+ }
+ Enum {
name: "Alignment"
values: {
"AlignLeft": 1,
@@ -466,7 +473,8 @@ Module {
"AA_DontShowShortcutsInContextMenus": 28,
"AA_CompressTabletEvents": 29,
"AA_DisableWindowContextHelpButton": 30,
- "AA_AttributeCount": 31
+ "AA_DisableSessionManager": 31,
+ "AA_AttributeCount": 32
}
}
Enum {
@@ -1081,7 +1089,8 @@ Module {
values: {
"PlainText": 0,
"RichText": 1,
- "AutoText": 2
+ "AutoText": 2,
+ "MarkdownText": 3
}
}
Enum {
diff --git a/src/imports/folderlistmodel/plugins.qmltypes b/src/imports/folderlistmodel/plugins.qmltypes
index 6f5466dbda..0fdbae66d3 100644
--- a/src/imports/folderlistmodel/plugins.qmltypes
+++ b/src/imports/folderlistmodel/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable Qt.labs.folderlistmodel 2.13'
+// 'qmlplugindump -nonrelocatable Qt.labs.folderlistmodel 2.14'
Module {
dependencies: ["QtQuick 2.0"]
diff --git a/src/imports/labsmodels/plugins.qmltypes b/src/imports/labsmodels/plugins.qmltypes
index 6272069060..f2a5752422 100644
--- a/src/imports/labsmodels/plugins.qmltypes
+++ b/src/imports/labsmodels/plugins.qmltypes
@@ -9,6 +9,280 @@ import QtQuick.tooling 1.2
Module {
dependencies: []
Component {
+ name: "QAbstractItemModel"
+ prototype: "QObject"
+ Enum {
+ name: "LayoutChangeHint"
+ values: {
+ "NoLayoutChangeHint": 0,
+ "VerticalSortHint": 1,
+ "HorizontalSortHint": 2
+ }
+ }
+ Enum {
+ name: "CheckIndexOption"
+ values: {
+ "NoOption": 0,
+ "IndexIsValid": 1,
+ "DoNotUseParent": 2,
+ "ParentIsInvalid": 4
+ }
+ }
+ Signal {
+ name: "dataChanged"
+ Parameter { name: "topLeft"; type: "QModelIndex" }
+ Parameter { name: "bottomRight"; type: "QModelIndex" }
+ Parameter { name: "roles"; type: "QVector<int>" }
+ }
+ Signal {
+ name: "dataChanged"
+ Parameter { name: "topLeft"; type: "QModelIndex" }
+ Parameter { name: "bottomRight"; type: "QModelIndex" }
+ }
+ Signal {
+ name: "headerDataChanged"
+ Parameter { name: "orientation"; type: "Qt::Orientation" }
+ Parameter { name: "first"; type: "int" }
+ Parameter { name: "last"; type: "int" }
+ }
+ Signal {
+ name: "layoutChanged"
+ Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" }
+ Parameter { name: "hint"; type: "QAbstractItemModel::LayoutChangeHint" }
+ }
+ Signal {
+ name: "layoutChanged"
+ Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" }
+ }
+ Signal { name: "layoutChanged" }
+ Signal {
+ name: "layoutAboutToBeChanged"
+ Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" }
+ Parameter { name: "hint"; type: "QAbstractItemModel::LayoutChangeHint" }
+ }
+ Signal {
+ name: "layoutAboutToBeChanged"
+ Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" }
+ }
+ Signal { name: "layoutAboutToBeChanged" }
+ Signal {
+ name: "rowsAboutToBeInserted"
+ Parameter { name: "parent"; type: "QModelIndex" }
+ Parameter { name: "first"; type: "int" }
+ Parameter { name: "last"; type: "int" }
+ }
+ Signal {
+ name: "rowsInserted"
+ Parameter { name: "parent"; type: "QModelIndex" }
+ Parameter { name: "first"; type: "int" }
+ Parameter { name: "last"; type: "int" }
+ }
+ Signal {
+ name: "rowsAboutToBeRemoved"
+ Parameter { name: "parent"; type: "QModelIndex" }
+ Parameter { name: "first"; type: "int" }
+ Parameter { name: "last"; type: "int" }
+ }
+ Signal {
+ name: "rowsRemoved"
+ Parameter { name: "parent"; type: "QModelIndex" }
+ Parameter { name: "first"; type: "int" }
+ Parameter { name: "last"; type: "int" }
+ }
+ Signal {
+ name: "columnsAboutToBeInserted"
+ Parameter { name: "parent"; type: "QModelIndex" }
+ Parameter { name: "first"; type: "int" }
+ Parameter { name: "last"; type: "int" }
+ }
+ Signal {
+ name: "columnsInserted"
+ Parameter { name: "parent"; type: "QModelIndex" }
+ Parameter { name: "first"; type: "int" }
+ Parameter { name: "last"; type: "int" }
+ }
+ Signal {
+ name: "columnsAboutToBeRemoved"
+ Parameter { name: "parent"; type: "QModelIndex" }
+ Parameter { name: "first"; type: "int" }
+ Parameter { name: "last"; type: "int" }
+ }
+ Signal {
+ name: "columnsRemoved"
+ Parameter { name: "parent"; type: "QModelIndex" }
+ Parameter { name: "first"; type: "int" }
+ Parameter { name: "last"; type: "int" }
+ }
+ Signal { name: "modelAboutToBeReset" }
+ Signal { name: "modelReset" }
+ Signal {
+ name: "rowsAboutToBeMoved"
+ Parameter { name: "sourceParent"; type: "QModelIndex" }
+ Parameter { name: "sourceStart"; type: "int" }
+ Parameter { name: "sourceEnd"; type: "int" }
+ Parameter { name: "destinationParent"; type: "QModelIndex" }
+ Parameter { name: "destinationRow"; type: "int" }
+ }
+ Signal {
+ name: "rowsMoved"
+ Parameter { name: "parent"; type: "QModelIndex" }
+ Parameter { name: "start"; type: "int" }
+ Parameter { name: "end"; type: "int" }
+ Parameter { name: "destination"; type: "QModelIndex" }
+ Parameter { name: "row"; type: "int" }
+ }
+ Signal {
+ name: "columnsAboutToBeMoved"
+ Parameter { name: "sourceParent"; type: "QModelIndex" }
+ Parameter { name: "sourceStart"; type: "int" }
+ Parameter { name: "sourceEnd"; type: "int" }
+ Parameter { name: "destinationParent"; type: "QModelIndex" }
+ Parameter { name: "destinationColumn"; type: "int" }
+ }
+ Signal {
+ name: "columnsMoved"
+ Parameter { name: "parent"; type: "QModelIndex" }
+ Parameter { name: "start"; type: "int" }
+ Parameter { name: "end"; type: "int" }
+ Parameter { name: "destination"; type: "QModelIndex" }
+ Parameter { name: "column"; type: "int" }
+ }
+ Method { name: "submit"; type: "bool" }
+ Method { name: "revert" }
+ Method {
+ name: "hasIndex"
+ type: "bool"
+ Parameter { name: "row"; type: "int" }
+ Parameter { name: "column"; type: "int" }
+ Parameter { name: "parent"; type: "QModelIndex" }
+ }
+ Method {
+ name: "hasIndex"
+ type: "bool"
+ Parameter { name: "row"; type: "int" }
+ Parameter { name: "column"; type: "int" }
+ }
+ Method {
+ name: "index"
+ type: "QModelIndex"
+ Parameter { name: "row"; type: "int" }
+ Parameter { name: "column"; type: "int" }
+ Parameter { name: "parent"; type: "QModelIndex" }
+ }
+ Method {
+ name: "index"
+ type: "QModelIndex"
+ Parameter { name: "row"; type: "int" }
+ Parameter { name: "column"; type: "int" }
+ }
+ Method {
+ name: "parent"
+ type: "QModelIndex"
+ Parameter { name: "child"; type: "QModelIndex" }
+ }
+ Method {
+ name: "sibling"
+ type: "QModelIndex"
+ Parameter { name: "row"; type: "int" }
+ Parameter { name: "column"; type: "int" }
+ Parameter { name: "idx"; type: "QModelIndex" }
+ }
+ Method {
+ name: "rowCount"
+ type: "int"
+ Parameter { name: "parent"; type: "QModelIndex" }
+ }
+ Method { name: "rowCount"; type: "int" }
+ Method {
+ name: "columnCount"
+ type: "int"
+ Parameter { name: "parent"; type: "QModelIndex" }
+ }
+ Method { name: "columnCount"; type: "int" }
+ Method {
+ name: "hasChildren"
+ type: "bool"
+ Parameter { name: "parent"; type: "QModelIndex" }
+ }
+ Method { name: "hasChildren"; type: "bool" }
+ Method {
+ name: "data"
+ type: "QVariant"
+ Parameter { name: "index"; type: "QModelIndex" }
+ Parameter { name: "role"; type: "int" }
+ }
+ Method {
+ name: "data"
+ type: "QVariant"
+ Parameter { name: "index"; type: "QModelIndex" }
+ }
+ Method {
+ name: "setData"
+ type: "bool"
+ Parameter { name: "index"; type: "QModelIndex" }
+ Parameter { name: "value"; type: "QVariant" }
+ Parameter { name: "role"; type: "int" }
+ }
+ Method {
+ name: "setData"
+ type: "bool"
+ Parameter { name: "index"; type: "QModelIndex" }
+ Parameter { name: "value"; type: "QVariant" }
+ }
+ Method {
+ name: "headerData"
+ type: "QVariant"
+ Parameter { name: "section"; type: "int" }
+ Parameter { name: "orientation"; type: "Qt::Orientation" }
+ Parameter { name: "role"; type: "int" }
+ }
+ Method {
+ name: "headerData"
+ type: "QVariant"
+ Parameter { name: "section"; type: "int" }
+ Parameter { name: "orientation"; type: "Qt::Orientation" }
+ }
+ Method {
+ name: "fetchMore"
+ Parameter { name: "parent"; type: "QModelIndex" }
+ }
+ Method {
+ name: "canFetchMore"
+ type: "bool"
+ Parameter { name: "parent"; type: "QModelIndex" }
+ }
+ Method {
+ name: "flags"
+ type: "Qt::ItemFlags"
+ Parameter { name: "index"; type: "QModelIndex" }
+ }
+ Method {
+ name: "match"
+ type: "QModelIndexList"
+ Parameter { name: "start"; type: "QModelIndex" }
+ Parameter { name: "role"; type: "int" }
+ Parameter { name: "value"; type: "QVariant" }
+ Parameter { name: "hits"; type: "int" }
+ Parameter { name: "flags"; type: "Qt::MatchFlags" }
+ }
+ Method {
+ name: "match"
+ type: "QModelIndexList"
+ Parameter { name: "start"; type: "QModelIndex" }
+ Parameter { name: "role"; type: "int" }
+ Parameter { name: "value"; type: "QVariant" }
+ Parameter { name: "hits"; type: "int" }
+ }
+ Method {
+ name: "match"
+ type: "QModelIndexList"
+ Parameter { name: "start"; type: "QModelIndex" }
+ Parameter { name: "role"; type: "int" }
+ Parameter { name: "value"; type: "QVariant" }
+ }
+ }
+ Component { name: "QAbstractTableModel"; prototype: "QAbstractItemModel" }
+ Component {
name: "QQmlAbstractDelegateComponent"
prototype: "QQmlComponent"
exports: ["Qt.labs.qmlmodels/AbstractDelegateComponent 1.0"]
@@ -38,4 +312,103 @@ Module {
Property { name: "role"; type: "string" }
Property { name: "choices"; type: "QQmlDelegateChoice"; isList: true; isReadonly: true }
}
+ Component {
+ name: "QQmlTableModel"
+ defaultProperty: "columns"
+ prototype: "QAbstractTableModel"
+ exports: ["Qt.labs.qmlmodels/TableModel 1.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "columnCount"; type: "int"; isReadonly: true }
+ Property { name: "rowCount"; type: "int"; isReadonly: true }
+ Property { name: "rows"; type: "QVariant" }
+ Property { name: "columns"; type: "QQmlTableModelColumn"; isList: true; isReadonly: true }
+ Method {
+ name: "appendRow"
+ Parameter { name: "row"; type: "QVariant" }
+ }
+ Method { name: "clear" }
+ Method {
+ name: "getRow"
+ type: "QVariant"
+ Parameter { name: "rowIndex"; type: "int" }
+ }
+ Method {
+ name: "insertRow"
+ Parameter { name: "rowIndex"; type: "int" }
+ Parameter { name: "row"; type: "QVariant" }
+ }
+ Method {
+ name: "moveRow"
+ Parameter { name: "fromRowIndex"; type: "int" }
+ Parameter { name: "toRowIndex"; type: "int" }
+ Parameter { name: "rows"; type: "int" }
+ }
+ Method {
+ name: "moveRow"
+ Parameter { name: "fromRowIndex"; type: "int" }
+ Parameter { name: "toRowIndex"; type: "int" }
+ }
+ Method {
+ name: "removeRow"
+ Parameter { name: "rowIndex"; type: "int" }
+ Parameter { name: "rows"; type: "int" }
+ }
+ Method {
+ name: "removeRow"
+ Parameter { name: "rowIndex"; type: "int" }
+ }
+ Method {
+ name: "setRow"
+ Parameter { name: "rowIndex"; type: "int" }
+ Parameter { name: "row"; type: "QVariant" }
+ }
+ Method {
+ name: "data"
+ type: "QVariant"
+ Parameter { name: "index"; type: "QModelIndex" }
+ Parameter { name: "role"; type: "string" }
+ }
+ Method {
+ name: "setData"
+ type: "bool"
+ Parameter { name: "index"; type: "QModelIndex" }
+ Parameter { name: "role"; type: "string" }
+ Parameter { name: "value"; type: "QVariant" }
+ }
+ }
+ Component {
+ name: "QQmlTableModelColumn"
+ prototype: "QObject"
+ exports: ["Qt.labs.qmlmodels/TableModelColumn 1.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "display"; type: "QJSValue" }
+ Property { name: "setDisplay"; type: "QJSValue" }
+ Property { name: "decoration"; type: "QJSValue" }
+ Property { name: "setDecoration"; type: "QJSValue" }
+ Property { name: "edit"; type: "QJSValue" }
+ Property { name: "setEdit"; type: "QJSValue" }
+ Property { name: "toolTip"; type: "QJSValue" }
+ Property { name: "setToolTip"; type: "QJSValue" }
+ Property { name: "statusTip"; type: "QJSValue" }
+ Property { name: "setStatusTip"; type: "QJSValue" }
+ Property { name: "whatsThis"; type: "QJSValue" }
+ Property { name: "setWhatsThis"; type: "QJSValue" }
+ Property { name: "font"; type: "QJSValue" }
+ Property { name: "setFont"; type: "QJSValue" }
+ Property { name: "textAlignment"; type: "QJSValue" }
+ Property { name: "setTextAlignment"; type: "QJSValue" }
+ Property { name: "background"; type: "QJSValue" }
+ Property { name: "setBackground"; type: "QJSValue" }
+ Property { name: "foreground"; type: "QJSValue" }
+ Property { name: "setForeground"; type: "QJSValue" }
+ Property { name: "checkState"; type: "QJSValue" }
+ Property { name: "setCheckState"; type: "QJSValue" }
+ Property { name: "accessibleText"; type: "QJSValue" }
+ Property { name: "setAccessibleText"; type: "QJSValue" }
+ Property { name: "accessibleDescription"; type: "QJSValue" }
+ Property { name: "setAccessibleDescription"; type: "QJSValue" }
+ Property { name: "sizeHint"; type: "QJSValue" }
+ Property { name: "setSizeHint"; type: "QJSValue" }
+ Signal { name: "indexChanged" }
+ }
}
diff --git a/src/imports/layouts/plugins.qmltypes b/src/imports/layouts/plugins.qmltypes
index 22e8d79ece..6015164511 100644
--- a/src/imports/layouts/plugins.qmltypes
+++ b/src/imports/layouts/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable QtQuick.Layouts 1.13'
+// 'qmlplugindump -nonrelocatable QtQuick.Layouts 1.14'
Module {
dependencies: ["QtQuick 2.0"]
diff --git a/src/imports/layouts/qquicklinearlayout.cpp b/src/imports/layouts/qquicklinearlayout.cpp
index fa51ef1f2f..af7b1b7340 100644
--- a/src/imports/layouts/qquicklinearlayout.cpp
+++ b/src/imports/layouts/qquicklinearlayout.cpp
@@ -759,7 +759,7 @@ QQuickLinearLayout::QQuickLinearLayout(Qt::Orientation orientation,
\since QtQuick.Layouts 1.1
This property holds the layout direction of the row layout - it controls whether items are laid
- out from left ro right or right to left. If \c Qt.RightToLeft is specified,
+ out from left to right or right to left. If \c Qt.RightToLeft is specified,
left-aligned items will be right-aligned and right-aligned items will be left-aligned.
Possible values:
@@ -776,7 +776,7 @@ QQuickLinearLayout::QQuickLinearLayout(Qt::Orientation orientation,
\since QtQuick.Layouts 1.1
This property holds the layout direction of the column layout - it controls whether items are laid
- out from left ro right or right to left. If \c Qt.RightToLeft is specified,
+ out from left to right or right to left. If \c Qt.RightToLeft is specified,
left-aligned items will be right-aligned and right-aligned items will be left-aligned.
Possible values:
diff --git a/src/imports/localstorage/plugins.qmltypes b/src/imports/localstorage/plugins.qmltypes
index 3c8c1404f2..6ed334cc9d 100644
--- a/src/imports/localstorage/plugins.qmltypes
+++ b/src/imports/localstorage/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQuick.LocalStorage 2.13'
+// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQuick.LocalStorage 2.14'
Module {
dependencies: []
diff --git a/src/imports/models/plugins.qmltypes b/src/imports/models/plugins.qmltypes
index 6e112c41b6..0d8b94df23 100644
--- a/src/imports/models/plugins.qmltypes
+++ b/src/imports/models/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQml.Models 2.13'
+// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQml.Models 2.14'
Module {
dependencies: []
@@ -441,8 +441,8 @@ Module {
Signal { name: "defaultIncludeChanged" }
Signal {
name: "changed"
- Parameter { name: "removed"; type: "QQmlV4Handle" }
- Parameter { name: "inserted"; type: "QQmlV4Handle" }
+ Parameter { name: "removed"; type: "QJSValue" }
+ Parameter { name: "inserted"; type: "QJSValue" }
}
Method {
name: "insert"
@@ -478,7 +478,7 @@ Module {
}
Method {
name: "get"
- type: "QQmlV4Handle"
+ type: "QJSValue"
Parameter { name: "index"; type: "int" }
}
}
@@ -496,6 +496,7 @@ Module {
exportMetaObjectRevisions: [0]
Property { name: "count"; type: "int"; isReadonly: true }
Property { name: "dynamicRoles"; type: "bool" }
+ Property { name: "agent"; revision: 14; type: "QObject"; isReadonly: true; isPointer: true }
Method { name: "clear" }
Method {
name: "remove"
@@ -511,13 +512,61 @@ Module {
}
Method {
name: "get"
- type: "QQmlV4Handle"
+ type: "QJSValue"
Parameter { name: "index"; type: "int" }
}
Method {
name: "set"
Parameter { name: "index"; type: "int" }
- Parameter { type: "QQmlV4Handle" }
+ Parameter { name: "value"; type: "QJSValue" }
+ }
+ Method {
+ name: "setProperty"
+ Parameter { name: "index"; type: "int" }
+ Parameter { name: "property"; type: "string" }
+ Parameter { name: "value"; type: "QVariant" }
+ }
+ Method {
+ name: "move"
+ Parameter { name: "from"; type: "int" }
+ Parameter { name: "to"; type: "int" }
+ Parameter { name: "count"; type: "int" }
+ }
+ Method { name: "sync" }
+ }
+ Component {
+ name: "QQmlListModelWorkerAgent"
+ prototype: "QObject"
+ Property { name: "count"; type: "int"; isReadonly: true }
+ Property { name: "engine"; type: "QV4::ExecutionEngine"; isPointer: true }
+ Signal {
+ name: "engineChanged"
+ Parameter { name: "engine"; type: "QV4::ExecutionEngine"; isPointer: true }
+ }
+ Method { name: "addref" }
+ Method { name: "release" }
+ Method { name: "clear" }
+ Method {
+ name: "remove"
+ Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
+ }
+ Method {
+ name: "append"
+ Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
+ }
+ Method {
+ name: "insert"
+ Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
+ }
+ Method {
+ name: "get"
+ type: "QJSValue"
+ Parameter { name: "index"; type: "int" }
+ }
+ Method {
+ name: "set"
+ Parameter { name: "index"; type: "int" }
+ Parameter { name: "value"; type: "QJSValue" }
}
Method {
name: "setProperty"
@@ -592,4 +641,18 @@ Module {
prototype: "QObject"
Property { name: "index"; type: "int"; isReadonly: true }
}
+ Component {
+ name: "QQuickPackage"
+ defaultProperty: "data"
+ prototype: "QObject"
+ exports: ["QtQml.Models/Package 2.14"]
+ exportMetaObjectRevisions: [0]
+ attachedType: "QQuickPackageAttached"
+ Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
+ }
+ Component {
+ name: "QQuickPackageAttached"
+ prototype: "QObject"
+ Property { name: "name"; type: "string" }
+ }
}
diff --git a/src/imports/particles/plugins.qmltypes b/src/imports/particles/plugins.qmltypes
index b6db00e683..0fe5dc808c 100644
--- a/src/imports/particles/plugins.qmltypes
+++ b/src/imports/particles/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable QtQuick.Particles 2.13'
+// 'qmlplugindump -nonrelocatable QtQuick.Particles 2.14'
Module {
dependencies: ["QtQuick 2.0"]
@@ -165,7 +165,7 @@ Module {
Property { name: "acceleration"; type: "QQuickDirection"; isPointer: true }
Signal {
name: "affectParticles"
- Parameter { name: "particles"; type: "QQmlV4Handle" }
+ Parameter { name: "particles"; type: "QJSValue" }
Parameter { name: "dt"; type: "double" }
}
Signal {
@@ -668,7 +668,7 @@ Module {
Property { name: "velocityFromMovement"; type: "double" }
Signal {
name: "emitParticles"
- Parameter { name: "particles"; type: "QQmlV4Handle" }
+ Parameter { name: "particles"; type: "QJSValue" }
}
Signal {
name: "particlesPerSecondChanged"
@@ -1084,8 +1084,8 @@ Module {
Property { name: "emitWidth"; type: "double" }
Signal {
name: "emitFollowParticles"
- Parameter { name: "particles"; type: "QQmlV4Handle" }
- Parameter { name: "followed"; type: "QQmlV4Handle" }
+ Parameter { name: "particles"; type: "QJSValue" }
+ Parameter { name: "followed"; type: "QJSValue" }
}
Signal {
name: "particlesPerParticlePerSecondChanged"
diff --git a/src/imports/qtqml/dependencies.json b/src/imports/qtqml/dependencies.json
new file mode 100644
index 0000000000..0d4f101c7a
--- /dev/null
+++ b/src/imports/qtqml/dependencies.json
@@ -0,0 +1,2 @@
+[
+]
diff --git a/src/imports/qtqml/plugins.qmltypes b/src/imports/qtqml/plugins.qmltypes
index d548a78dd0..63f5bada9b 100644
--- a/src/imports/qtqml/plugins.qmltypes
+++ b/src/imports/qtqml/plugins.qmltypes
@@ -4,14 +4,14 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable -noforceqtquick QtQml 2.13'
+// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQml 2.14'
Module {
dependencies: []
Component {
name: "QObject"
- exports: ["QtQml/QtObject 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: ["QML/QtObject 1.0", "QtQml/QtObject 2.0"]
+ exportMetaObjectRevisions: [0, 0]
Property { name: "objectName"; type: "string" }
Signal {
name: "objectNameChanged"
@@ -27,13 +27,27 @@ Module {
Component {
name: "QQmlBind"
prototype: "QObject"
- exports: ["QtQml/Binding 2.0", "QtQml/Binding 2.8"]
- exportMetaObjectRevisions: [0, 8]
+ exports: [
+ "QtQml/Binding 2.0",
+ "QtQml/Binding 2.14",
+ "QtQml/Binding 2.8"
+ ]
+ exportMetaObjectRevisions: [0, 14, 8]
+ Enum {
+ name: "RestorationMode"
+ values: {
+ "RestoreNone": 0,
+ "RestoreBinding": 1,
+ "RestoreValue": 2,
+ "RestoreBindingOrValue": 3
+ }
+ }
Property { name: "target"; type: "QObject"; isPointer: true }
Property { name: "property"; type: "string" }
Property { name: "value"; type: "QVariant" }
Property { name: "when"; type: "bool" }
Property { name: "delayed"; revision: 8; type: "bool" }
+ Property { name: "restoreMode"; revision: 14; type: "RestorationMode" }
}
Component {
name: "QQmlComponent"
@@ -94,11 +108,11 @@ Module {
name: "QQmlConnections"
prototype: "QObject"
exports: ["QtQml/Connections 2.0", "QtQml/Connections 2.3"]
- exportMetaObjectRevisions: [0, 1]
+ exportMetaObjectRevisions: [0, 3]
Property { name: "target"; type: "QObject"; isPointer: true }
- Property { name: "enabled"; revision: 1; type: "bool" }
+ Property { name: "enabled"; revision: 3; type: "bool" }
Property { name: "ignoreUnknownSignals"; type: "bool" }
- Signal { name: "enabledChanged"; revision: 1 }
+ Signal { name: "enabledChanged"; revision: 3 }
}
Component {
name: "QQmlInstanceModel"
@@ -199,7 +213,7 @@ Module {
name: "QQmlLoggingCategory"
prototype: "QObject"
exports: ["QtQml/LoggingCategory 2.12", "QtQml/LoggingCategory 2.8"]
- exportMetaObjectRevisions: [1, 0]
+ exportMetaObjectRevisions: [12, 0]
Enum {
name: "DefaultLogLevel"
values: {
@@ -211,7 +225,7 @@ Module {
}
}
Property { name: "name"; type: "string" }
- Property { name: "defaultLogLevel"; revision: 1; type: "DefaultLogLevel" }
+ Property { name: "defaultLogLevel"; revision: 12; type: "DefaultLogLevel" }
}
Component {
name: "QQmlTimer"
diff --git a/src/imports/qtquick2/plugins.qmltypes b/src/imports/qtquick2/plugins.qmltypes
index f006c874da..c8aae2087d 100644
--- a/src/imports/qtquick2/plugins.qmltypes
+++ b/src/imports/qtquick2/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQuick 2.13'
+// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQuick 2.14'
Module {
dependencies: []
@@ -529,8 +529,8 @@ Module {
Signal { name: "defaultIncludeChanged" }
Signal {
name: "changed"
- Parameter { name: "removed"; type: "QQmlV4Handle" }
- Parameter { name: "inserted"; type: "QQmlV4Handle" }
+ Parameter { name: "removed"; type: "QJSValue" }
+ Parameter { name: "inserted"; type: "QJSValue" }
}
Method {
name: "insert"
@@ -566,7 +566,7 @@ Module {
}
Method {
name: "get"
- type: "QQmlV4Handle"
+ type: "QJSValue"
Parameter { name: "index"; type: "int" }
}
}
@@ -646,6 +646,7 @@ Module {
exportMetaObjectRevisions: [0]
Property { name: "count"; type: "int"; isReadonly: true }
Property { name: "dynamicRoles"; type: "bool" }
+ Property { name: "agent"; revision: 14; type: "QObject"; isReadonly: true; isPointer: true }
Method { name: "clear" }
Method {
name: "remove"
@@ -661,13 +662,61 @@ Module {
}
Method {
name: "get"
- type: "QQmlV4Handle"
+ type: "QJSValue"
Parameter { name: "index"; type: "int" }
}
Method {
name: "set"
Parameter { name: "index"; type: "int" }
- Parameter { type: "QQmlV4Handle" }
+ Parameter { name: "value"; type: "QJSValue" }
+ }
+ Method {
+ name: "setProperty"
+ Parameter { name: "index"; type: "int" }
+ Parameter { name: "property"; type: "string" }
+ Parameter { name: "value"; type: "QVariant" }
+ }
+ Method {
+ name: "move"
+ Parameter { name: "from"; type: "int" }
+ Parameter { name: "to"; type: "int" }
+ Parameter { name: "count"; type: "int" }
+ }
+ Method { name: "sync" }
+ }
+ Component {
+ name: "QQmlListModelWorkerAgent"
+ prototype: "QObject"
+ Property { name: "count"; type: "int"; isReadonly: true }
+ Property { name: "engine"; type: "QV4::ExecutionEngine"; isPointer: true }
+ Signal {
+ name: "engineChanged"
+ Parameter { name: "engine"; type: "QV4::ExecutionEngine"; isPointer: true }
+ }
+ Method { name: "addref" }
+ Method { name: "release" }
+ Method { name: "clear" }
+ Method {
+ name: "remove"
+ Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
+ }
+ Method {
+ name: "append"
+ Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
+ }
+ Method {
+ name: "insert"
+ Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
+ }
+ Method {
+ name: "get"
+ type: "QJSValue"
+ Parameter { name: "index"; type: "int" }
+ }
+ Method {
+ name: "set"
+ Parameter { name: "index"; type: "int" }
+ Parameter { name: "value"; type: "QJSValue" }
}
Method {
name: "setProperty"
@@ -1300,7 +1349,7 @@ Module {
}
Property { name: "available"; type: "bool"; isReadonly: true }
Property { name: "contextType"; type: "string" }
- Property { name: "context"; type: "QQmlV4Handle"; isReadonly: true }
+ Property { name: "context"; type: "QJSValue"; isReadonly: true }
Property { name: "canvasSize"; type: "QSizeF" }
Property { name: "tileSize"; type: "QSize" }
Property { name: "canvasWindow"; type: "QRectF" }
@@ -1480,9 +1529,19 @@ Module {
prototype: "QQuickMultiPointHandler"
exports: ["QtQuick/DragHandler 2.12"]
exportMetaObjectRevisions: [0]
+ Enum {
+ name: "SnapMode"
+ values: {
+ "NoSnap": 0,
+ "SnapAuto": 1,
+ "SnapIfPressedOutsideTarget": 2,
+ "SnapAlways": 3
+ }
+ }
Property { name: "xAxis"; type: "QQuickDragAxis"; isReadonly: true; isPointer: true }
Property { name: "yAxis"; type: "QQuickDragAxis"; isReadonly: true; isPointer: true }
Property { name: "translation"; type: "QVector2D"; isReadonly: true }
+ Property { name: "snapMode"; type: "SnapMode" }
}
Component {
name: "QQuickDropArea"
@@ -1959,7 +2018,13 @@ Module {
"Unknown": 0,
"Software": 1,
"OpenGL": 2,
- "Direct3D12": 3
+ "Direct3D12": 3,
+ "OpenVG": 4,
+ "OpenGLRhi": 5,
+ "Direct3D11Rhi": 6,
+ "VulkanRhi": 7,
+ "MetalRhi": 8,
+ "NullRhi": 9
}
}
Enum {
@@ -1967,7 +2032,8 @@ Module {
values: {
"UnknownShadingLanguage": 0,
"GLSL": 1,
- "HLSL": 2
+ "HLSL": 2,
+ "RhiShader": 3
}
}
Enum {
@@ -2131,7 +2197,7 @@ Module {
"QtQuick/Image 2.3",
"QtQuick/Image 2.5"
]
- exportMetaObjectRevisions: [0, 1, 2]
+ exportMetaObjectRevisions: [0, 3, 5]
Enum {
name: "HAlignment"
values: {
@@ -2165,8 +2231,8 @@ Module {
Property { name: "paintedHeight"; type: "double"; isReadonly: true }
Property { name: "horizontalAlignment"; type: "HAlignment" }
Property { name: "verticalAlignment"; type: "VAlignment" }
- Property { name: "mipmap"; revision: 1; type: "bool" }
- Property { name: "autoTransform"; revision: 2; type: "bool" }
+ Property { name: "mipmap"; revision: 3; type: "bool" }
+ Property { name: "autoTransform"; revision: 5; type: "bool" }
Signal { name: "paintedGeometryChanged" }
Signal {
name: "horizontalAlignmentChanged"
@@ -2178,10 +2244,10 @@ Module {
}
Signal {
name: "mipmapChanged"
- revision: 1
+ revision: 3
Parameter { type: "bool" }
}
- Signal { name: "autoTransformChanged"; revision: 2 }
+ Signal { name: "autoTransformChanged"; revision: 5 }
}
Component {
name: "QQuickImageBase"
@@ -2242,7 +2308,7 @@ Module {
"QtQuick/Item 2.4",
"QtQuick/Item 2.7"
]
- exportMetaObjectRevisions: [0, 1, 11, 2, 7]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Enum {
name: "Flags"
values: {
@@ -2362,14 +2428,14 @@ Module {
Method { name: "update" }
Method {
name: "grabToImage"
- revision: 2
+ revision: 4
type: "bool"
Parameter { name: "callback"; type: "QJSValue" }
Parameter { name: "targetSize"; type: "QSize" }
}
Method {
name: "grabToImage"
- revision: 2
+ revision: 4
type: "bool"
Parameter { name: "callback"; type: "QJSValue" }
}
@@ -2502,7 +2568,7 @@ Module {
"QtQuick/ItemView 2.7"
]
isCreatable: false
- exportMetaObjectRevisions: [1, 13, 2, 7]
+ exportMetaObjectRevisions: [1, 13, 3, 7]
Enum {
name: "LayoutDirection"
values: {
@@ -2546,8 +2612,8 @@ Module {
Property { name: "keyNavigationWraps"; type: "bool" }
Property { name: "keyNavigationEnabled"; revision: 7; type: "bool" }
Property { name: "cacheBuffer"; type: "int" }
- Property { name: "displayMarginBeginning"; revision: 2; type: "int" }
- Property { name: "displayMarginEnd"; revision: 2; type: "int" }
+ Property { name: "displayMarginBeginning"; revision: 3; type: "int" }
+ Property { name: "displayMarginEnd"; revision: 3; type: "int" }
Property { name: "layoutDirection"; type: "Qt::LayoutDirection" }
Property { name: "effectiveLayoutDirection"; type: "Qt::LayoutDirection"; isReadonly: true }
Property { name: "verticalLayoutDirection"; type: "VerticalLayoutDirection" }
@@ -2858,7 +2924,7 @@ Module {
"QtQuick/ListView 2.4",
"QtQuick/ListView 2.7"
]
- exportMetaObjectRevisions: [0, 1, 2, 7]
+ exportMetaObjectRevisions: [0, 1, 4, 7]
attachedType: "QQuickListViewAttached"
Enum {
name: "Orientation"
@@ -2899,10 +2965,10 @@ Module {
Property { name: "section"; type: "QQuickViewSection"; isReadonly: true; isPointer: true }
Property { name: "currentSection"; type: "string"; isReadonly: true }
Property { name: "snapMode"; type: "SnapMode" }
- Property { name: "headerPositioning"; revision: 2; type: "HeaderPositioning" }
- Property { name: "footerPositioning"; revision: 2; type: "FooterPositioning" }
- Signal { name: "headerPositioningChanged"; revision: 2 }
- Signal { name: "footerPositioningChanged"; revision: 2 }
+ Property { name: "headerPositioning"; revision: 4; type: "HeaderPositioning" }
+ Property { name: "footerPositioning"; revision: 4; type: "FooterPositioning" }
+ Signal { name: "headerPositioningChanged"; revision: 4 }
+ Signal { name: "footerPositioningChanged"; revision: 4 }
Method { name: "incrementCurrentIndex" }
Method { name: "decrementCurrentIndex" }
}
@@ -2952,13 +3018,13 @@ Module {
"QtQuick/MouseArea 2.5",
"QtQuick/MouseArea 2.9"
]
- exportMetaObjectRevisions: [0, 1, 2, 9]
+ exportMetaObjectRevisions: [0, 4, 5, 9]
Property { name: "mouseX"; type: "double"; isReadonly: true }
Property { name: "mouseY"; type: "double"; isReadonly: true }
Property { name: "containsMouse"; type: "bool"; isReadonly: true }
Property { name: "pressed"; type: "bool"; isReadonly: true }
Property { name: "enabled"; type: "bool" }
- Property { name: "scrollGestureEnabled"; revision: 2; type: "bool" }
+ Property { name: "scrollGestureEnabled"; revision: 5; type: "bool" }
Property { name: "pressedButtons"; type: "Qt::MouseButtons"; isReadonly: true }
Property { name: "acceptedButtons"; type: "Qt::MouseButtons" }
Property { name: "hoverEnabled"; type: "bool" }
@@ -2966,10 +3032,10 @@ Module {
Property { name: "preventStealing"; type: "bool" }
Property { name: "propagateComposedEvents"; type: "bool" }
Property { name: "cursorShape"; type: "Qt::CursorShape" }
- Property { name: "containsPress"; revision: 1; type: "bool"; isReadonly: true }
+ Property { name: "containsPress"; revision: 4; type: "bool"; isReadonly: true }
Property { name: "pressAndHoldInterval"; revision: 9; type: "int" }
Signal { name: "hoveredChanged" }
- Signal { name: "scrollGestureEnabledChanged"; revision: 2 }
+ Signal { name: "scrollGestureEnabledChanged"; revision: 5 }
Signal {
name: "positionChanged"
Parameter { name: "mouse"; type: "QQuickMouseEvent"; isPointer: true }
@@ -3009,7 +3075,7 @@ Module {
Signal { name: "entered" }
Signal { name: "exited" }
Signal { name: "canceled" }
- Signal { name: "containsPressChanged"; revision: 1 }
+ Signal { name: "containsPressChanged"; revision: 4 }
Signal { name: "pressAndHoldIntervalChanged"; revision: 9 }
}
Component {
@@ -3172,13 +3238,21 @@ Module {
name: "QQuickPath"
defaultProperty: "pathElements"
prototype: "QObject"
- exports: ["QtQuick/Path 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: ["QtQuick/Path 2.0", "QtQuick/Path 2.14"]
+ exportMetaObjectRevisions: [0, 14]
Property { name: "pathElements"; type: "QQuickPathElement"; isList: true; isReadonly: true }
Property { name: "startX"; type: "double" }
Property { name: "startY"; type: "double" }
Property { name: "closed"; type: "bool"; isReadonly: true }
+ Property { name: "scale"; revision: 14; type: "QSizeF" }
Signal { name: "changed" }
+ Signal { name: "scaleChanged"; revision: 14 }
+ Method {
+ name: "pointAtPercent"
+ revision: 14
+ type: "QPointF"
+ Parameter { name: "t"; type: "double" }
+ }
}
Component {
name: "QQuickPathAngleArc"
@@ -3250,7 +3324,7 @@ Module {
name: "QQuickPathArc"
prototype: "QQuickCurve"
exports: ["QtQuick/PathArc 2.0", "QtQuick/PathArc 2.9"]
- exportMetaObjectRevisions: [0, 2]
+ exportMetaObjectRevisions: [0, 9]
Enum {
name: "ArcDirection"
values: {
@@ -3262,8 +3336,8 @@ Module {
Property { name: "radiusY"; type: "double" }
Property { name: "useLargeArc"; type: "bool" }
Property { name: "direction"; type: "ArcDirection" }
- Property { name: "xAxisRotation"; revision: 2; type: "double" }
- Signal { name: "xAxisRotationChanged"; revision: 2 }
+ Property { name: "xAxisRotation"; revision: 9; type: "double" }
+ Signal { name: "xAxisRotationChanged"; revision: 9 }
}
Component {
name: "QQuickPathAttribute"
@@ -3322,6 +3396,14 @@ Module {
exportMetaObjectRevisions: [0]
}
Component {
+ name: "QQuickPathMultiline"
+ prototype: "QQuickCurve"
+ exports: ["QtQuick/PathMultiline 2.14"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "start"; type: "QPointF"; isReadonly: true }
+ Property { name: "paths"; type: "QVariantList" }
+ }
+ Component {
name: "QQuickPathPercent"
prototype: "QQuickPathElement"
exports: ["QtQuick/PathPercent 2.0"]
@@ -3329,6 +3411,14 @@ Module {
Property { name: "value"; type: "double" }
}
Component {
+ name: "QQuickPathPolyline"
+ prototype: "QQuickCurve"
+ exports: ["QtQuick/PathPolyline 2.14"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "start"; type: "QPointF"; isReadonly: true }
+ Property { name: "path"; type: "QVariantList" }
+ }
+ Component {
name: "QQuickPathQuad"
prototype: "QQuickCurve"
exports: ["QtQuick/PathQuad 2.0"]
@@ -3508,7 +3598,7 @@ Module {
defaultProperty: "data"
prototype: "QQuickItem"
exports: ["QtQuick/PinchArea 2.0", "QtQuick/PinchArea 2.5"]
- exportMetaObjectRevisions: [0, 1]
+ exportMetaObjectRevisions: [0, 5]
Property { name: "enabled"; type: "bool" }
Property { name: "pinch"; type: "QQuickPinch"; isReadonly: true; isPointer: true }
Signal {
@@ -3525,7 +3615,7 @@ Module {
}
Signal {
name: "smartZoom"
- revision: 1
+ revision: 5
Parameter { name: "pinch"; type: "QQuickPinchEvent"; isPointer: true }
}
}
@@ -3920,7 +4010,7 @@ Module {
defaultProperty: "data"
prototype: "QQuickItem"
exports: ["QtQuick/ShaderEffect 2.0", "QtQuick/ShaderEffect 2.4"]
- exportMetaObjectRevisions: [0, 1]
+ exportMetaObjectRevisions: [0, 4]
Enum {
name: "CullMode"
values: {
@@ -3944,7 +4034,7 @@ Module {
Property { name: "cullMode"; type: "CullMode" }
Property { name: "log"; type: "string"; isReadonly: true }
Property { name: "status"; type: "Status"; isReadonly: true }
- Property { name: "supportsAtlasTextures"; revision: 1; type: "bool" }
+ Property { name: "supportsAtlasTextures"; revision: 4; type: "bool" }
}
Component {
name: "QQuickShaderEffectMesh"
@@ -3963,7 +4053,7 @@ Module {
"QtQuick/ShaderEffectSource 2.6",
"QtQuick/ShaderEffectSource 2.9"
]
- exportMetaObjectRevisions: [0, 1, 2]
+ exportMetaObjectRevisions: [0, 6, 9]
Enum {
name: "WrapMode"
values: {
@@ -3998,8 +4088,8 @@ Module {
Property { name: "hideSource"; type: "bool" }
Property { name: "mipmap"; type: "bool" }
Property { name: "recursive"; type: "bool" }
- Property { name: "textureMirroring"; revision: 1; type: "TextureMirroring" }
- Property { name: "samples"; revision: 2; type: "int" }
+ Property { name: "textureMirroring"; revision: 6; type: "TextureMirroring" }
+ Property { name: "samples"; revision: 9; type: "int" }
Signal { name: "scheduledUpdateCompleted" }
Method { name: "scheduleUpdate" }
}
@@ -4011,11 +4101,11 @@ Module {
"QtQuick/Shortcut 2.6",
"QtQuick/Shortcut 2.9"
]
- exportMetaObjectRevisions: [0, 1, 9]
+ exportMetaObjectRevisions: [0, 6, 9]
Property { name: "sequence"; type: "QVariant" }
Property { name: "sequences"; revision: 9; type: "QVariantList" }
- Property { name: "nativeText"; revision: 1; type: "string"; isReadonly: true }
- Property { name: "portableText"; revision: 1; type: "string"; isReadonly: true }
+ Property { name: "nativeText"; revision: 6; type: "string"; isReadonly: true }
+ Property { name: "portableText"; revision: 6; type: "string"; isReadonly: true }
Property { name: "enabled"; type: "bool" }
Property { name: "autoRepeat"; type: "bool" }
Property { name: "context"; type: "Qt::ShortcutContext" }
@@ -4229,7 +4319,7 @@ Module {
exports: ["QtQuick/State 2.0"]
exportMetaObjectRevisions: [0]
Property { name: "name"; type: "string" }
- Property { name: "when"; type: "QQmlBinding"; isPointer: true }
+ Property { name: "when"; type: "bool" }
Property { name: "extend"; type: "string" }
Property { name: "changes"; type: "QQuickStateOperation"; isList: true; isReadonly: true }
Signal { name: "completed" }
@@ -4340,8 +4430,8 @@ Module {
name: "QQuickTableView"
defaultProperty: "flickableData"
prototype: "QQuickFlickable"
- exports: ["QtQuick/TableView 2.12"]
- exportMetaObjectRevisions: [0]
+ exports: ["QtQuick/TableView 2.12", "QtQuick/TableView 2.14"]
+ exportMetaObjectRevisions: [0, 14]
attachedType: "QQuickTableViewAttached"
Property { name: "rows"; type: "int"; isReadonly: true }
Property { name: "columns"; type: "int"; isReadonly: true }
@@ -4354,6 +4444,10 @@ Module {
Property { name: "reuseItems"; type: "bool" }
Property { name: "contentWidth"; type: "double" }
Property { name: "contentHeight"; type: "double" }
+ Property { name: "syncView"; revision: 14; type: "QQuickTableView"; isPointer: true }
+ Property { name: "syncDirection"; revision: 14; type: "Qt::Orientations" }
+ Signal { name: "syncViewChanged"; revision: 14 }
+ Signal { name: "syncDirectionChanged"; revision: 14 }
Method { name: "forceLayout" }
}
Component {
@@ -4440,6 +4534,7 @@ Module {
values: {
"PlainText": 0,
"RichText": 1,
+ "MarkdownText": 3,
"AutoText": 2,
"StyledText": 4
}
@@ -4631,7 +4726,8 @@ Module {
values: {
"PlainText": 0,
"RichText": 1,
- "AutoText": 2
+ "AutoText": 2,
+ "MarkdownText": 3
}
}
Enum {
@@ -4892,7 +4988,7 @@ Module {
"QtQuick/TextInput 2.7",
"QtQuick/TextInput 2.9"
]
- exportMetaObjectRevisions: [0, 2, 3, 6, 7, 9]
+ exportMetaObjectRevisions: [0, 2, 4, 6, 7, 9]
Enum {
name: "EchoMode"
values: {
@@ -4976,7 +5072,7 @@ Module {
Property { name: "echoMode"; type: "EchoMode" }
Property { name: "activeFocusOnPress"; type: "bool" }
Property { name: "passwordCharacter"; type: "string" }
- Property { name: "passwordMaskDelay"; revision: 3; type: "int" }
+ Property { name: "passwordMaskDelay"; revision: 4; type: "int" }
Property { name: "displayText"; type: "string"; isReadonly: true }
Property { name: "preeditText"; revision: 7; type: "string"; isReadonly: true }
Property { name: "autoScroll"; type: "bool" }
@@ -5036,7 +5132,7 @@ Module {
}
Signal {
name: "passwordMaskDelayChanged"
- revision: 3
+ revision: 4
Parameter { name: "delay"; type: "int" }
}
Signal { name: "preeditTextChanged"; revision: 7 }
@@ -5093,7 +5189,7 @@ Module {
}
Method {
name: "ensureVisible"
- revision: 3
+ revision: 4
Parameter { name: "position"; type: "int" }
}
Method { name: "clear"; revision: 7 }
@@ -5117,7 +5213,7 @@ Module {
}
Method {
name: "inputMethodQuery"
- revision: 3
+ revision: 4
type: "QVariant"
Parameter { name: "query"; type: "Qt::InputMethodQuery" }
Parameter { name: "argument"; type: "QVariant" }
@@ -5272,6 +5368,24 @@ Module {
Property { name: "accepted"; type: "bool" }
}
Component {
+ name: "QQuickWheelHandler"
+ prototype: "QQuickSinglePointHandler"
+ exports: ["QtQuick/WheelHandler 2.14"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "orientation"; type: "Qt::Orientation" }
+ Property { name: "invertible"; type: "bool" }
+ Property { name: "activeTimeout"; type: "double" }
+ Property { name: "rotation"; type: "double" }
+ Property { name: "rotationScale"; type: "double" }
+ Property { name: "property"; type: "string" }
+ Property { name: "targetScaleMultiplier"; type: "double" }
+ Property { name: "targetTransformAroundCursor"; type: "bool" }
+ Signal {
+ name: "wheel"
+ Parameter { name: "event"; type: "QQuickPointerScrollEvent"; isPointer: true }
+ }
+ }
+ Component {
name: "QQuickWorkerScript"
prototype: "QObject"
exports: ["QtQuick/WorkerScript 2.0"]
@@ -5279,7 +5393,7 @@ Module {
Property { name: "source"; type: "QUrl" }
Signal {
name: "message"
- Parameter { name: "messageObject"; type: "QQmlV4Handle" }
+ Parameter { name: "messageObject"; type: "QJSValue" }
}
Method {
name: "sendMessage"
@@ -5310,8 +5424,31 @@ Module {
}
}
Component {
+ name: "QRegularExpressionValidator"
+ prototype: "QValidator"
+ exports: ["QtQuick/RegularExpressionValidator 2.14"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "regularExpression"; type: "QRegularExpression" }
+ Signal {
+ name: "regularExpressionChanged"
+ Parameter { name: "re"; type: "QRegularExpression" }
+ }
+ Method {
+ name: "setRegularExpression"
+ Parameter { name: "re"; type: "QRegularExpression" }
+ }
+ }
+ Component {
name: "QValidator"
prototype: "QObject"
+ Enum {
+ name: "State"
+ values: {
+ "Invalid": 0,
+ "Intermediate": 1,
+ "Acceptable": 2
+ }
+ }
Signal { name: "changed" }
}
}
diff --git a/src/imports/shapes/plugins.qmltypes b/src/imports/shapes/plugins.qmltypes
index b78c5a1130..cd779e7149 100644
--- a/src/imports/shapes/plugins.qmltypes
+++ b/src/imports/shapes/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable QtQuick.Shapes 1.13'
+// 'qmlplugindump -nonrelocatable QtQuick.Shapes 1.14'
Module {
dependencies: ["QtQuick 2.0"]
@@ -89,8 +89,11 @@ Module {
name: "QQuickShapePath"
defaultProperty: "pathElements"
prototype: "QQuickPath"
- exports: ["QtQuick.Shapes/ShapePath 1.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Shapes/ShapePath 1.0",
+ "QtQuick.Shapes/ShapePath 1.14"
+ ]
+ exportMetaObjectRevisions: [0, 14]
Enum {
name: "FillRule"
values: {
@@ -132,6 +135,7 @@ Module {
Property { name: "dashOffset"; type: "double" }
Property { name: "dashPattern"; type: "QVector<qreal>" }
Property { name: "fillGradient"; type: "QQuickShapeGradient"; isPointer: true }
+ Property { name: "scale"; revision: 14; type: "QSizeF" }
Signal { name: "shapePathChanged" }
}
Component {
diff --git a/src/imports/statemachine/plugins.qmltypes b/src/imports/statemachine/plugins.qmltypes
index f92aeaa080..541b1cc114 100644
--- a/src/imports/statemachine/plugins.qmltypes
+++ b/src/imports/statemachine/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQml.StateMachine 1.13'
+// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQml.StateMachine 1.14'
Module {
dependencies: []
diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp
index c5873c1058..a8bcfa2764 100644
--- a/src/imports/testlib/main.cpp
+++ b/src/imports/testlib/main.cpp
@@ -150,7 +150,7 @@ public:
qmlRegisterType<QuickTestEvent>(uri,1,0,"TestEvent");
qmlRegisterType<QuickTestEvent>(uri,1,2,"TestEvent");
qmlRegisterType<QuickTestUtil>(uri,1,0,"TestUtil");
- qmlRegisterType<QQuickTouchEventSequence>();
+ qmlRegisterAnonymousType<QQuickTouchEventSequence>(uri);
qmlRegisterModule(uri, 1, 15);
}
diff --git a/src/imports/testlib/plugins.qmltypes b/src/imports/testlib/plugins.qmltypes
index 1e081d82ff..6a1371e5f1 100644
--- a/src/imports/testlib/plugins.qmltypes
+++ b/src/imports/testlib/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable QtTest 1.13'
+// 'qmlplugindump -nonrelocatable QtTest 1.14'
Module {
dependencies: ["QtQuick 2.0", "QtQuick.Window 2.0"]
@@ -343,7 +343,7 @@ Module {
Property { name: "dragThreshold"; type: "int"; isReadonly: true }
Method {
name: "typeName"
- type: "QQmlV4Handle"
+ type: "QJSValue"
Parameter { name: "v"; type: "QVariant" }
}
Method {
@@ -354,10 +354,10 @@ Module {
}
Method {
name: "callerFile"
- type: "QQmlV4Handle"
+ type: "QJSValue"
Parameter { name: "frameIndex"; type: "int" }
}
- Method { name: "callerFile"; type: "QQmlV4Handle" }
+ Method { name: "callerFile"; type: "QJSValue" }
Method {
name: "callerLine"
type: "int"
diff --git a/src/imports/wavefrontmesh/plugins.qmltypes b/src/imports/wavefrontmesh/plugins.qmltypes
index b9dd9e4c46..4e6a1dca73 100644
--- a/src/imports/wavefrontmesh/plugins.qmltypes
+++ b/src/imports/wavefrontmesh/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable Qt.labs.wavefrontmesh 1.13'
+// 'qmlplugindump -nonrelocatable Qt.labs.wavefrontmesh 1.14'
Module {
dependencies: ["QtQuick 2.0"]
diff --git a/src/imports/window/plugins.qmltypes b/src/imports/window/plugins.qmltypes
index b5786ed5a6..82b7ce0fc5 100644
--- a/src/imports/window/plugins.qmltypes
+++ b/src/imports/window/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable QtQuick.Window 2.13'
+// 'qmlplugindump -nonrelocatable QtQuick.Window 2.14'
Module {
dependencies: ["QtQuick 2.0"]
@@ -26,7 +26,7 @@ Module {
prototype: "QObject"
exports: ["QtQuick.Window/Screen 2.0", "QtQuick.Window/Screen 2.3"]
isCreatable: false
- exportMetaObjectRevisions: [0, 1]
+ exportMetaObjectRevisions: [0, 3]
attachedType: "QQuickScreenAttached"
}
Component {
@@ -48,7 +48,7 @@ Module {
"QtQuick.Window/ScreenInfo 2.3"
]
isCreatable: false
- exportMetaObjectRevisions: [10, 2]
+ exportMetaObjectRevisions: [10, 3]
Property { name: "name"; type: "string"; isReadonly: true }
Property { name: "manufacturer"; revision: 10; type: "string"; isReadonly: true }
Property { name: "model"; revision: 10; type: "string"; isReadonly: true }
@@ -62,14 +62,14 @@ Module {
Property { name: "devicePixelRatio"; type: "double"; isReadonly: true }
Property { name: "primaryOrientation"; type: "Qt::ScreenOrientation"; isReadonly: true }
Property { name: "orientation"; type: "Qt::ScreenOrientation"; isReadonly: true }
- Property { name: "virtualX"; revision: 1; type: "int"; isReadonly: true }
- Property { name: "virtualY"; revision: 1; type: "int"; isReadonly: true }
+ Property { name: "virtualX"; revision: 3; type: "int"; isReadonly: true }
+ Property { name: "virtualY"; revision: 3; type: "int"; isReadonly: true }
Signal { name: "manufacturerChanged"; revision: 10 }
Signal { name: "modelChanged"; revision: 10 }
Signal { name: "serialNumberChanged"; revision: 10 }
Signal { name: "desktopGeometryChanged" }
- Signal { name: "virtualXChanged"; revision: 1 }
- Signal { name: "virtualYChanged"; revision: 1 }
+ Signal { name: "virtualXChanged"; revision: 3 }
+ Signal { name: "virtualYChanged"; revision: 3 }
}
Component {
name: "QQuickWindow"
@@ -140,6 +140,8 @@ Module {
Parameter { name: "error"; type: "QQuickWindow::SceneGraphError" }
Parameter { name: "message"; type: "string" }
}
+ Signal { name: "beforeRenderPassRecording"; revision: 14 }
+ Signal { name: "afterRenderPassRecording"; revision: 14 }
Method { name: "update" }
Method { name: "releaseResources" }
}
@@ -164,11 +166,11 @@ Module {
"QtQuick.Window/Window 2.2",
"QtQuick.Window/Window 2.3"
]
- exportMetaObjectRevisions: [0, 13, 1, 2]
+ exportMetaObjectRevisions: [0, 13, 2, 3]
attachedType: "QQuickWindowAttached"
Property { name: "visible"; type: "bool" }
Property { name: "visibility"; type: "Visibility" }
- Property { name: "screen"; revision: 2; type: "QObject"; isPointer: true }
+ Property { name: "screen"; revision: 3; type: "QObject"; isPointer: true }
Signal {
name: "visibleChanged"
Parameter { name: "arg"; type: "bool" }
@@ -177,7 +179,7 @@ Module {
name: "visibilityChanged"
Parameter { name: "visibility"; type: "QWindow::Visibility" }
}
- Signal { name: "screenChanged"; revision: 2 }
+ Signal { name: "screenChanged"; revision: 3 }
}
Component {
name: "QWindow"
diff --git a/src/imports/workerscript/plugins.qmltypes b/src/imports/workerscript/plugins.qmltypes
new file mode 100644
index 0000000000..b1d6107022
--- /dev/null
+++ b/src/imports/workerscript/plugins.qmltypes
@@ -0,0 +1,26 @@
+import QtQuick.tooling 1.2
+
+// This file describes the plugin-supplied types contained in the library.
+// It is used for QML tooling purposes only.
+//
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQml.WorkerScript 2.14'
+
+Module {
+ dependencies: []
+ Component {
+ name: "QQuickWorkerScript"
+ prototype: "QObject"
+ exports: ["QtQml.WorkerScript/WorkerScript 2.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "source"; type: "QUrl" }
+ Signal {
+ name: "message"
+ Parameter { name: "messageObject"; type: "QJSValue" }
+ }
+ Method {
+ name: "sendMessage"
+ Parameter { type: "QQmlV4Function"; isPointer: true }
+ }
+ }
+}
diff --git a/src/particles/particles.qrc b/src/particles/particles.qrc
index ad44cf406e..c7102b9aa5 100644
--- a/src/particles/particles.qrc
+++ b/src/particles/particles.qrc
@@ -16,5 +16,16 @@
<file>shaders/customparticletemplate_core.vert</file>
<file>shaders/imageparticle_core.frag</file>
<file>shaders/imageparticle_core.vert</file>
+
+ <file>shaders_ng/imageparticle_simple.vert.qsb</file>
+ <file>shaders_ng/imageparticle_simple.frag.qsb</file>
+ <file>shaders_ng/imageparticle_tabled.vert.qsb</file>
+ <file>shaders_ng/imageparticle_tabled.frag.qsb</file>
+ <file>shaders_ng/imageparticle_deformed.vert.qsb</file>
+ <file>shaders_ng/imageparticle_deformed.frag.qsb</file>
+ <file>shaders_ng/imageparticle_sprite.vert.qsb</file>
+ <file>shaders_ng/imageparticle_sprite.frag.qsb</file>
+ <file>shaders_ng/imageparticle_colored.vert.qsb</file>
+ <file>shaders_ng/imageparticle_colored.frag.qsb</file>
</qresource>
</RCC>
diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp
index ae1ef80026..649fbb30c2 100644
--- a/src/particles/qquickimageparticle.cpp
+++ b/src/particles/qquickimageparticle.cpp
@@ -1,6 +1,6 @@
-/****************************************************************************
+/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -41,7 +41,6 @@
#include <private/qsgadaptationlayer_p.h>
#include <private/qquickitem_p.h>
#include <QtQuick/qsgnode.h>
-#include <QtQuick/qsgtexturematerial.h>
#include <QtQuick/qsgtexture.h>
#include <QFile>
#include <QRandomGenerator>
@@ -56,13 +55,15 @@
#include <private/qqmlglobal_p.h>
#include <QtQml/qqmlinfo.h>
#include <cmath>
+#include <QtGui/private/qrhi_p.h>
QT_BEGIN_NAMESPACE
-//TODO: Make it larger on desktop? Requires fixing up shader code with the same define
+// Must match the shader code
#define UNIFORM_ARRAY_SIZE 64
const qreal CONV = 0.017453292519943295;
+
class ImageMaterialData
{
public:
@@ -85,13 +86,10 @@ class ImageMaterialData
QSizeF animSheetSize;
};
-class TabledMaterialData : public ImageMaterialData {};
-class TabledMaterial : public QSGSimpleMaterialShader<TabledMaterialData>
+class TabledMaterialShader : public QSGMaterialShader
{
- QSG_DECLARE_SIMPLE_SHADER(TabledMaterial, TabledMaterialData)
-
public:
- TabledMaterial()
+ TabledMaterialShader()
{
QSGShaderSourceBuilder builder;
const bool isES = QOpenGLContext::currentContext()->isOpenGLES();
@@ -122,36 +120,47 @@ public:
const char *vertexShader() const override { return m_vertex_code.constData(); }
const char *fragmentShader() const override { return m_fragment_code.constData(); }
- QList<QByteArray> attributes() const override {
- return QList<QByteArray>() << "vPosTex" << "vData" << "vVec"
- << "vColor" << "vDeformVec" << "vRotation";
- };
+ char const *const *attributeNames() const override
+ {
+ static const char *const attr[] = { "vPosTex", "vData", "vVec", "vColor", "vDeformVec", "vRotation", nullptr };
+ return attr;
+ }
void initialize() override {
- QSGSimpleMaterialShader<TabledMaterialData>::initialize();
program()->bind();
program()->setUniformValue("_qt_texture", 0);
program()->setUniformValue("colortable", 1);
glFuncs = QOpenGLContext::currentContext()->functions();
+ m_matrix_id = program()->uniformLocation("qt_Matrix");
+ m_opacity_id = program()->uniformLocation("qt_Opacity");
m_timestamp_id = program()->uniformLocation("timestamp");
m_entry_id = program()->uniformLocation("entry");
m_sizetable_id = program()->uniformLocation("sizetable");
m_opacitytable_id = program()->uniformLocation("opacitytable");
}
- void updateState(const TabledMaterialData* d, const TabledMaterialData*) override {
+ void updateState(const RenderState &renderState, QSGMaterial *mat, QSGMaterial *) override {
+ ImageMaterialData *state = static_cast<ImageMaterial *>(mat)->state();
+
+ if (renderState.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, renderState.combinedMatrix());
+ if (renderState.isOpacityDirty() && m_opacity_id >= 0)
+ program()->setUniformValue(m_opacity_id, renderState.opacity());
+
glFuncs->glActiveTexture(GL_TEXTURE1);
- d->colorTable->bind();
+ state->colorTable->bind();
glFuncs->glActiveTexture(GL_TEXTURE0);
- d->texture->bind();
+ state->texture->bind();
- program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
- program()->setUniformValue(m_entry_id, (float) d->entry);
- program()->setUniformValueArray(m_sizetable_id, (const float*) d->sizeTable, UNIFORM_ARRAY_SIZE, 1);
- program()->setUniformValueArray(m_opacitytable_id, (const float*) d->opacityTable, UNIFORM_ARRAY_SIZE, 1);
+ program()->setUniformValue(m_timestamp_id, (float) state->timestamp);
+ program()->setUniformValue(m_entry_id, (float) state->entry);
+ program()->setUniformValueArray(m_sizetable_id, (const float*) state->sizeTable, UNIFORM_ARRAY_SIZE, 1);
+ program()->setUniformValueArray(m_opacitytable_id, (const float*) state->opacityTable, UNIFORM_ARRAY_SIZE, 1);
}
+ int m_matrix_id;
+ int m_opacity_id;
int m_entry_id;
int m_timestamp_id;
int m_sizetable_id;
@@ -161,13 +170,91 @@ public:
QOpenGLFunctions* glFuncs;
};
-class DeformableMaterialData : public ImageMaterialData {};
-class DeformableMaterial : public QSGSimpleMaterialShader<DeformableMaterialData>
+class TabledMaterialRhiShader : public QSGMaterialRhiShader
+{
+public:
+ TabledMaterialRhiShader()
+ {
+ setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_tabled.vert.qsb"));
+ setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_tabled.frag.qsb"));
+ }
+
+ bool updateUniformData(const RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override
+ {
+ QByteArray *buf = renderState.uniformData();
+ Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4));
+
+ if (renderState.isMatrixDirty()) {
+ const QMatrix4x4 m = renderState.combinedMatrix();
+ memcpy(buf->data(), m.constData(), 64);
+ }
+
+ if (renderState.isOpacityDirty()) {
+ const float opacity = renderState.opacity();
+ memcpy(buf->data() + 64, &opacity, 4);
+ }
+
+ ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
+
+ float entry = float(state->entry);
+ memcpy(buf->data() + 68, &entry, 4);
+
+ float timestamp = float(state->timestamp);
+ memcpy(buf->data() + 72, &timestamp, 4);
+
+ float *p = reinterpret_cast<float *>(buf->data() + 80);
+ for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) {
+ *p = state->sizeTable[i];
+ p += 4;
+ }
+ p = reinterpret_cast<float *>(buf->data() + 80 + (UNIFORM_ARRAY_SIZE * 4 * 4));
+ for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) {
+ *p = state->opacityTable[i];
+ p += 4;
+ }
+
+ return true;
+ }
+
+ void updateSampledImage(const RenderState &renderState, int binding, QSGTexture **texture,
+ QSGMaterial *newMaterial, QSGMaterial *) override
+ {
+ ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
+ if (binding == 2) {
+ state->colorTable->updateRhiTexture(renderState.rhi(), renderState.resourceUpdateBatch());
+ *texture = state->colorTable;
+ } else if (binding == 1) {
+ state->texture->updateRhiTexture(renderState.rhi(), renderState.resourceUpdateBatch());
+ *texture = state->texture;
+ }
+ }
+};
+
+class TabledMaterial : public ImageMaterial
{
- QSG_DECLARE_SIMPLE_SHADER(DeformableMaterial, DeformableMaterialData)
+public:
+ TabledMaterial() { setFlag(SupportsRhiShader, true); }
+ QSGMaterialShader *createShader() const override {
+ if (flags().testFlag(RhiShaderWanted))
+ return new TabledMaterialRhiShader;
+ else
+ return new TabledMaterialShader;
+ }
+ QSGMaterialType *type() const override { return &m_type; }
+
+ ImageMaterialData *state() override { return &m_state; }
+private:
+ static QSGMaterialType m_type;
+ ImageMaterialData m_state;
+};
+
+QSGMaterialType TabledMaterial::m_type;
+
+class DeformableMaterialShader : public QSGMaterialShader
+{
public:
- DeformableMaterial()
+ DeformableMaterialShader()
{
QSGShaderSourceBuilder builder;
const bool isES = QOpenGLContext::currentContext()->isOpenGLES();
@@ -196,27 +283,38 @@ public:
const char *vertexShader() const override { return m_vertex_code.constData(); }
const char *fragmentShader() const override { return m_fragment_code.constData(); }
- QList<QByteArray> attributes() const override {
- return QList<QByteArray>() << "vPosTex" << "vData" << "vVec"
- << "vColor" << "vDeformVec" << "vRotation";
- };
+ char const *const *attributeNames() const override
+ {
+ static const char *const attr[] = { "vPosTex", "vData", "vVec", "vColor", "vDeformVec", "vRotation", nullptr };
+ return attr;
+ }
void initialize() override {
- QSGSimpleMaterialShader<DeformableMaterialData>::initialize();
program()->bind();
program()->setUniformValue("_qt_texture", 0);
glFuncs = QOpenGLContext::currentContext()->functions();
+ m_matrix_id = program()->uniformLocation("qt_Matrix");
+ m_opacity_id = program()->uniformLocation("qt_Opacity");
m_timestamp_id = program()->uniformLocation("timestamp");
m_entry_id = program()->uniformLocation("entry");
}
- void updateState(const DeformableMaterialData* d, const DeformableMaterialData*) override {
- d->texture->bind();
+ void updateState(const RenderState &renderState, QSGMaterial *mat, QSGMaterial *) override {
+ ImageMaterialData *state = static_cast<ImageMaterial *>(mat)->state();
+
+ if (renderState.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, renderState.combinedMatrix());
+ if (renderState.isOpacityDirty() && m_opacity_id >= 0)
+ program()->setUniformValue(m_opacity_id, renderState.opacity());
+
+ state->texture->bind();
- program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
- program()->setUniformValue(m_entry_id, (float) d->entry);
+ program()->setUniformValue(m_timestamp_id, (float) state->timestamp);
+ program()->setUniformValue(m_entry_id, (float) state->entry);
}
+ int m_matrix_id;
+ int m_opacity_id;
int m_entry_id;
int m_timestamp_id;
QByteArray m_vertex_code;
@@ -224,13 +322,77 @@ public:
QOpenGLFunctions* glFuncs;
};
-class SpriteMaterialData : public ImageMaterialData {};
-class SpriteMaterial : public QSGSimpleMaterialShader<SpriteMaterialData>
+class DeformableMaterialRhiShader : public QSGMaterialRhiShader
{
- QSG_DECLARE_SIMPLE_SHADER(SpriteMaterial, SpriteMaterialData)
+public:
+ DeformableMaterialRhiShader()
+ {
+ setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_deformed.vert.qsb"));
+ setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_deformed.frag.qsb"));
+ }
+ bool updateUniformData(const RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override
+ {
+ QByteArray *buf = renderState.uniformData();
+ Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4));
+
+ if (renderState.isMatrixDirty()) {
+ const QMatrix4x4 m = renderState.combinedMatrix();
+ memcpy(buf->data(), m.constData(), 64);
+ }
+
+ if (renderState.isOpacityDirty()) {
+ const float opacity = renderState.opacity();
+ memcpy(buf->data() + 64, &opacity, 4);
+ }
+
+ ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
+
+ float entry = float(state->entry);
+ memcpy(buf->data() + 68, &entry, 4);
+
+ float timestamp = float(state->timestamp);
+ memcpy(buf->data() + 72, &timestamp, 4);
+
+ return true;
+ }
+
+ void updateSampledImage(const RenderState &renderState, int binding, QSGTexture **texture,
+ QSGMaterial *newMaterial, QSGMaterial *) override
+ {
+ ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
+ if (binding == 1) {
+ state->texture->updateRhiTexture(renderState.rhi(), renderState.resourceUpdateBatch());
+ *texture = state->texture;
+ }
+ }
+};
+
+class DeformableMaterial : public ImageMaterial
+{
public:
- SpriteMaterial()
+ DeformableMaterial() { setFlag(SupportsRhiShader, true); }
+ QSGMaterialShader *createShader() const override {
+ if (flags().testFlag(RhiShaderWanted))
+ return new DeformableMaterialRhiShader;
+ else
+ return new DeformableMaterialShader;
+ }
+ QSGMaterialType *type() const override { return &m_type; }
+
+ ImageMaterialData *state() override { return &m_state; }
+
+private:
+ static QSGMaterialType m_type;
+ ImageMaterialData m_state;
+};
+
+QSGMaterialType DeformableMaterial::m_type;
+
+class SpriteMaterialShader : public QSGMaterialShader
+{
+public:
+ SpriteMaterialShader()
{
QSGShaderSourceBuilder builder;
const bool isES = QOpenGLContext::currentContext()->isOpenGLES();
@@ -263,17 +425,20 @@ public:
const char *vertexShader() const override { return m_vertex_code.constData(); }
const char *fragmentShader() const override { return m_fragment_code.constData(); }
- QList<QByteArray> attributes() const override {
- return QList<QByteArray>() << "vPosTex" << "vData" << "vVec"
- << "vColor" << "vDeformVec" << "vRotation" << "vAnimData" << "vAnimPos";
+ char const *const *attributeNames() const override
+ {
+ static const char *const attr[] = { "vPosTex", "vData", "vVec", "vColor", "vDeformVec", "vRotation",
+ "vAnimData", "vAnimPos", nullptr };
+ return attr;
}
void initialize() override {
- QSGSimpleMaterialShader<SpriteMaterialData>::initialize();
program()->bind();
program()->setUniformValue("_qt_texture", 0);
program()->setUniformValue("colortable", 1);
glFuncs = QOpenGLContext::currentContext()->functions();
+ m_matrix_id = program()->uniformLocation("qt_Matrix");
+ m_opacity_id = program()->uniformLocation("qt_Opacity");
//Don't actually expose the animSheetSize in the shader, it's currently only used for CPU calculations.
m_timestamp_id = program()->uniformLocation("timestamp");
m_entry_id = program()->uniformLocation("entry");
@@ -281,20 +446,29 @@ public:
m_opacitytable_id = program()->uniformLocation("opacitytable");
}
- void updateState(const SpriteMaterialData* d, const SpriteMaterialData*) override {
+ void updateState(const RenderState &renderState, QSGMaterial *mat, QSGMaterial *) override {
+ ImageMaterialData *state = static_cast<ImageMaterial *>(mat)->state();
+
+ if (renderState.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, renderState.combinedMatrix());
+ if (renderState.isOpacityDirty() && m_opacity_id >= 0)
+ program()->setUniformValue(m_opacity_id, renderState.opacity());
+
glFuncs->glActiveTexture(GL_TEXTURE1);
- d->colorTable->bind();
+ state->colorTable->bind();
// make sure we end by setting GL_TEXTURE0 as active texture
glFuncs->glActiveTexture(GL_TEXTURE0);
- d->texture->bind();
+ state->texture->bind();
- program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
- program()->setUniformValue(m_entry_id, (float) d->entry);
- program()->setUniformValueArray(m_sizetable_id, (const float*) d->sizeTable, 64, 1);
- program()->setUniformValueArray(m_opacitytable_id, (const float*) d->opacityTable, UNIFORM_ARRAY_SIZE, 1);
+ program()->setUniformValue(m_timestamp_id, (float) state->timestamp);
+ program()->setUniformValue(m_entry_id, (float) state->entry);
+ program()->setUniformValueArray(m_sizetable_id, (const float*) state->sizeTable, 64, 1);
+ program()->setUniformValueArray(m_opacitytable_id, (const float*) state->opacityTable, UNIFORM_ARRAY_SIZE, 1);
}
+ int m_matrix_id;
+ int m_opacity_id;
int m_timestamp_id;
int m_entry_id;
int m_sizetable_id;
@@ -304,13 +478,91 @@ public:
QOpenGLFunctions* glFuncs;
};
-class ColoredMaterialData : public ImageMaterialData {};
-class ColoredMaterial : public QSGSimpleMaterialShader<ColoredMaterialData>
+class SpriteMaterialRhiShader : public QSGMaterialRhiShader
{
- QSG_DECLARE_SIMPLE_SHADER(ColoredMaterial, ColoredMaterialData)
+public:
+ SpriteMaterialRhiShader()
+ {
+ setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_sprite.vert.qsb"));
+ setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_sprite.frag.qsb"));
+ }
+
+ bool updateUniformData(const RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override
+ {
+ QByteArray *buf = renderState.uniformData();
+ Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4));
+
+ if (renderState.isMatrixDirty()) {
+ const QMatrix4x4 m = renderState.combinedMatrix();
+ memcpy(buf->data(), m.constData(), 64);
+ }
+
+ if (renderState.isOpacityDirty()) {
+ const float opacity = renderState.opacity();
+ memcpy(buf->data() + 64, &opacity, 4);
+ }
+ ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
+
+ float entry = float(state->entry);
+ memcpy(buf->data() + 68, &entry, 4);
+
+ float timestamp = float(state->timestamp);
+ memcpy(buf->data() + 72, &timestamp, 4);
+
+ float *p = reinterpret_cast<float *>(buf->data() + 80);
+ for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) {
+ *p = state->sizeTable[i];
+ p += 4;
+ }
+ p = reinterpret_cast<float *>(buf->data() + 80 + (UNIFORM_ARRAY_SIZE * 4 * 4));
+ for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) {
+ *p = state->opacityTable[i];
+ p += 4;
+ }
+
+ return true;
+ }
+
+ void updateSampledImage(const RenderState &renderState, int binding, QSGTexture **texture,
+ QSGMaterial *newMaterial, QSGMaterial *) override
+ {
+ ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
+ if (binding == 2) {
+ state->colorTable->updateRhiTexture(renderState.rhi(), renderState.resourceUpdateBatch());
+ *texture = state->colorTable;
+ } else if (binding == 1) {
+ state->texture->updateRhiTexture(renderState.rhi(), renderState.resourceUpdateBatch());
+ *texture = state->texture;
+ }
+ }
+};
+
+class SpriteMaterial : public ImageMaterial
+{
public:
- ColoredMaterial()
+ SpriteMaterial() { setFlag(SupportsRhiShader, true); }
+ QSGMaterialShader *createShader() const override {
+ if (flags().testFlag(RhiShaderWanted))
+ return new SpriteMaterialRhiShader;
+ else
+ return new SpriteMaterialShader;
+ }
+ QSGMaterialType *type() const override { return &m_type; }
+
+ ImageMaterialData *state() override { return &m_state; }
+
+private:
+ static QSGMaterialType m_type;
+ ImageMaterialData m_state;
+};
+
+QSGMaterialType SpriteMaterial::m_type;
+
+class ColoredMaterialShader : public QSGMaterialShader
+{
+public:
+ ColoredMaterialShader()
{
QSGShaderSourceBuilder builder;
const bool isES = QOpenGLContext::currentContext()->isOpenGLES();
@@ -337,8 +589,23 @@ public:
const char *vertexShader() const override { return m_vertex_code.constData(); }
const char *fragmentShader() const override { return m_fragment_code.constData(); }
+ char const *const *attributeNames() const override
+ {
+ static const char *const attr[] = { "vPos", "vData", "vVec", "vColor", nullptr };
+ return attr;
+ }
+
+ void initialize() override {
+ program()->bind();
+ program()->setUniformValue("_qt_texture", 0);
+ glFuncs = QOpenGLContext::currentContext()->functions();
+ m_matrix_id = program()->uniformLocation("qt_Matrix");
+ m_opacity_id = program()->uniformLocation("qt_Opacity");
+ m_timestamp_id = program()->uniformLocation("timestamp");
+ m_entry_id = program()->uniformLocation("entry");
+ }
+
void activate() override {
- QSGSimpleMaterialShader<ColoredMaterialData>::activate();
#if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
glEnable(GL_POINT_SPRITE);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
@@ -346,33 +613,28 @@ public:
}
void deactivate() override {
- QSGSimpleMaterialShader<ColoredMaterialData>::deactivate();
#if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
glDisable(GL_POINT_SPRITE);
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
#endif
}
- QList<QByteArray> attributes() const override {
- return QList<QByteArray>() << "vPos" << "vData" << "vVec" << "vColor";
- }
+ void updateState(const RenderState &renderState, QSGMaterial *mat, QSGMaterial *) override {
+ ImageMaterialData *state = static_cast<ImageMaterial *>(mat)->state();
- void initialize() override {
- QSGSimpleMaterialShader<ColoredMaterialData>::initialize();
- program()->bind();
- program()->setUniformValue("_qt_texture", 0);
- glFuncs = QOpenGLContext::currentContext()->functions();
- m_timestamp_id = program()->uniformLocation("timestamp");
- m_entry_id = program()->uniformLocation("entry");
- }
+ if (renderState.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, renderState.combinedMatrix());
+ if (renderState.isOpacityDirty() && m_opacity_id >= 0)
+ program()->setUniformValue(m_opacity_id, renderState.opacity());
- void updateState(const ColoredMaterialData* d, const ColoredMaterialData*) override {
- d->texture->bind();
+ state->texture->bind();
- program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
- program()->setUniformValue(m_entry_id, (float) d->entry);
+ program()->setUniformValue(m_timestamp_id, (float) state->timestamp);
+ program()->setUniformValue(m_entry_id, (float) state->entry);
}
+ int m_matrix_id;
+ int m_opacity_id;
int m_timestamp_id;
int m_entry_id;
QByteArray m_vertex_code;
@@ -380,13 +642,77 @@ public:
QOpenGLFunctions* glFuncs;
};
-class SimpleMaterialData : public ImageMaterialData {};
-class SimpleMaterial : public QSGSimpleMaterialShader<SimpleMaterialData>
+class ColoredMaterialRhiShader : public QSGMaterialRhiShader
+{
+public:
+ ColoredMaterialRhiShader()
+ {
+ setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_colored.vert.qsb"));
+ setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_colored.frag.qsb"));
+ }
+
+ bool updateUniformData(const RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override
+ {
+ QByteArray *buf = renderState.uniformData();
+ Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4));
+
+ if (renderState.isMatrixDirty()) {
+ const QMatrix4x4 m = renderState.combinedMatrix();
+ memcpy(buf->data(), m.constData(), 64);
+ }
+
+ if (renderState.isOpacityDirty()) {
+ const float opacity = renderState.opacity();
+ memcpy(buf->data() + 64, &opacity, 4);
+ }
+
+ ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
+
+ float entry = float(state->entry);
+ memcpy(buf->data() + 68, &entry, 4);
+
+ float timestamp = float(state->timestamp);
+ memcpy(buf->data() + 72, &timestamp, 4);
+
+ return true;
+ }
+
+ void updateSampledImage(const RenderState &renderState, int binding, QSGTexture **texture,
+ QSGMaterial *newMaterial, QSGMaterial *) override
+ {
+ ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
+ if (binding == 1) {
+ state->texture->updateRhiTexture(renderState.rhi(), renderState.resourceUpdateBatch());
+ *texture = state->texture;
+ }
+ }
+};
+
+class ColoredMaterial : public ImageMaterial
{
- QSG_DECLARE_SIMPLE_SHADER(SimpleMaterial, SimpleMaterialData)
+public:
+ ColoredMaterial() { setFlag(SupportsRhiShader, true); }
+ QSGMaterialShader *createShader() const override {
+ if (flags().testFlag(RhiShaderWanted))
+ return new ColoredMaterialRhiShader;
+ else
+ return new ColoredMaterialShader;
+ }
+ QSGMaterialType *type() const override { return &m_type; }
+ ImageMaterialData *state() override { return &m_state; }
+
+private:
+ static QSGMaterialType m_type;
+ ImageMaterialData m_state;
+};
+
+QSGMaterialType ColoredMaterial::m_type;
+
+class SimpleMaterialShader : public QSGMaterialShader
+{
public:
- SimpleMaterial()
+ SimpleMaterialShader()
{
QSGShaderSourceBuilder builder;
const bool isES = QOpenGLContext::currentContext()->isOpenGLES();
@@ -411,8 +737,23 @@ public:
const char *vertexShader() const override { return m_vertex_code.constData(); }
const char *fragmentShader() const override { return m_fragment_code.constData(); }
+ char const *const *attributeNames() const override
+ {
+ static const char *const attr[] = { "vPos", "vData", "vVec", nullptr };
+ return attr;
+ }
+
+ void initialize() override {
+ program()->bind();
+ program()->setUniformValue("_qt_texture", 0);
+ glFuncs = QOpenGLContext::currentContext()->functions();
+ m_matrix_id = program()->uniformLocation("qt_Matrix");
+ m_opacity_id = program()->uniformLocation("qt_Opacity");
+ m_timestamp_id = program()->uniformLocation("timestamp");
+ m_entry_id = program()->uniformLocation("entry");
+ }
+
void activate() override {
- QSGSimpleMaterialShader<SimpleMaterialData>::activate();
#if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
glEnable(GL_POINT_SPRITE);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
@@ -420,33 +761,28 @@ public:
}
void deactivate() override {
- QSGSimpleMaterialShader<SimpleMaterialData>::deactivate();
#if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
glDisable(GL_POINT_SPRITE);
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
#endif
}
- QList<QByteArray> attributes() const override {
- return QList<QByteArray>() << "vPos" << "vData" << "vVec";
- }
+ void updateState(const RenderState &renderState, QSGMaterial *mat, QSGMaterial *) override {
+ ImageMaterialData *state = static_cast<ImageMaterial *>(mat)->state();
- void initialize() override {
- QSGSimpleMaterialShader<SimpleMaterialData>::initialize();
- program()->bind();
- program()->setUniformValue("_qt_texture", 0);
- glFuncs = QOpenGLContext::currentContext()->functions();
- m_timestamp_id = program()->uniformLocation("timestamp");
- m_entry_id = program()->uniformLocation("entry");
- }
+ if (renderState.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, renderState.combinedMatrix());
+ if (renderState.isOpacityDirty() && m_opacity_id >= 0)
+ program()->setUniformValue(m_opacity_id, renderState.opacity());
- void updateState(const SimpleMaterialData* d, const SimpleMaterialData*) override {
- d->texture->bind();
+ state->texture->bind();
- program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
- program()->setUniformValue(m_entry_id, (float) d->entry);
+ program()->setUniformValue(m_timestamp_id, (float) state->timestamp);
+ program()->setUniformValue(m_entry_id, (float) state->entry);
}
+ int m_matrix_id;
+ int m_opacity_id;
int m_timestamp_id;
int m_entry_id;
QByteArray m_vertex_code;
@@ -454,6 +790,73 @@ public:
QOpenGLFunctions* glFuncs;
};
+class SimpleMaterialRhiShader : public QSGMaterialRhiShader
+{
+public:
+ SimpleMaterialRhiShader()
+ {
+ setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_simple.vert.qsb"));
+ setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_simple.frag.qsb"));
+ }
+
+ bool updateUniformData(const RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override
+ {
+ QByteArray *buf = renderState.uniformData();
+ Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4));
+
+ if (renderState.isMatrixDirty()) {
+ const QMatrix4x4 m = renderState.combinedMatrix();
+ memcpy(buf->data(), m.constData(), 64);
+ }
+
+ if (renderState.isOpacityDirty()) {
+ const float opacity = renderState.opacity();
+ memcpy(buf->data() + 64, &opacity, 4);
+ }
+
+ ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
+
+ float entry = float(state->entry);
+ memcpy(buf->data() + 68, &entry, 4);
+
+ float timestamp = float(state->timestamp);
+ memcpy(buf->data() + 72, &timestamp, 4);
+
+ return true;
+ }
+
+ void updateSampledImage(const RenderState &renderState, int binding, QSGTexture **texture,
+ QSGMaterial *newMaterial, QSGMaterial *) override
+ {
+ ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
+ if (binding == 1) {
+ state->texture->updateRhiTexture(renderState.rhi(), renderState.resourceUpdateBatch());
+ *texture = state->texture;
+ }
+ }
+};
+
+class SimpleMaterial : public ImageMaterial
+{
+public:
+ SimpleMaterial() { setFlag(SupportsRhiShader, true); }
+ QSGMaterialShader *createShader() const override {
+ if (flags().testFlag(RhiShaderWanted))
+ return new SimpleMaterialRhiShader;
+ else
+ return new SimpleMaterialShader;
+ }
+ QSGMaterialType *type() const override { return &m_type; }
+
+ ImageMaterialData *state() override { return &m_state; }
+
+private:
+ static QSGMaterialType m_type;
+ ImageMaterialData m_state;
+};
+
+QSGMaterialType SimpleMaterial::m_type;
+
void fillUniformArrayFromImage(float* array, const QImage& img, int size)
{
if (img.isNull()){
@@ -726,6 +1129,8 @@ QQuickImageParticle::QQuickImageParticle(QQuickItem* parent)
, m_debugMode(false)
, m_entryEffect(Fade)
, m_startedImageLoading(0)
+ , m_rhi(nullptr)
+ , m_apiChecked(false)
{
setFlag(ItemHasContents);
}
@@ -1000,7 +1405,7 @@ void QQuickImageParticle::setEntryEffect(EntryEffect arg)
if (m_entryEffect != arg) {
m_entryEffect = arg;
if (m_material)
- getState<ImageMaterialData>(m_material)->entry = (qreal) m_entryEffect;
+ getState(m_material)->entry = (qreal) m_entryEffect;
emit entryEffectChanged(arg);
}
}
@@ -1224,7 +1629,7 @@ void QQuickImageParticle::buildParticleNodes(QSGNode** passThrough)
void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node)
{
- if (!QOpenGLContext::currentContext())
+ if (!m_rhi && !QOpenGLContext::currentContext())
return;
if (m_count * 4 > 0xffff) {
@@ -1271,28 +1676,38 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node)
}
}
}
+
+ if (!m_rhi) { // the RHI may be backed by GL but these checks should be obsolete in any case
#ifdef Q_OS_WIN
- if (perfLevel < Deformable) //QTBUG-24540 , point sprite 'extension' isn't working on windows.
- perfLevel = Deformable;
+ if (perfLevel < Deformable) //QTBUG-24540 , point sprite 'extension' isn't working on windows.
+ perfLevel = Deformable;
#endif
#ifdef Q_OS_MAC
- // OS X 10.8.3 introduced a bug in the AMD drivers, for at least the 2011 macbook pros,
- // causing point sprites who read gl_PointCoord in the frag shader to come out as
- // green-red blobs.
- const GLubyte *glVendor = QOpenGLContext::currentContext()->functions()->glGetString(GL_VENDOR);
- if (perfLevel < Deformable && glVendor && strstr((char *) glVendor, "ATI")) {
- perfLevel = Deformable;
- }
+ // macOS 10.8.3 introduced a bug in the AMD drivers, for at least the 2011 macbook pros,
+ // causing point sprites who read gl_PointCoord in the frag shader to come out as
+ // green-red blobs.
+ const GLubyte *glVendor = QOpenGLContext::currentContext()->functions()->glGetString(GL_VENDOR);
+ if (perfLevel < Deformable && glVendor && strstr((char *) glVendor, "ATI")) {
+ perfLevel = Deformable;
+ }
#endif
#ifdef Q_OS_LINUX
- // Nouveau drivers can potentially freeze a machine entirely when taking the point-sprite path.
- const GLubyte *glVendor = QOpenGLContext::currentContext()->functions()->glGetString(GL_VENDOR);
- if (perfLevel < Deformable && glVendor && strstr((const char *) glVendor, "nouveau"))
- perfLevel = Deformable;
+ // Nouveau drivers can potentially freeze a machine entirely when taking the point-sprite path.
+ const GLubyte *glVendor = QOpenGLContext::currentContext()->functions()->glGetString(GL_VENDOR);
+ if (perfLevel < Deformable && glVendor && strstr((const char *) glVendor, "nouveau"))
+ perfLevel = Deformable;
#endif
+ } else {
+ // Points with a size other than 1 are an optional feature with QRhi
+ // because some of the underlying APIs have no support for this.
+ // Therefore, avoid the point sprite path with APIs like Direct3D.
+ if (perfLevel < Deformable && !m_rhi->isFeatureSupported(QRhi::VertexShaderPointSize))
+ perfLevel = Deformable;
+ }
+
if (perfLevel >= Colored && !m_color.isValid())
m_color = QColor(Qt::white);//Hidden default, but different from unset
@@ -1308,6 +1723,7 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node)
bool imageLoaded = false;
switch (perfLevel) {//Fallthrough intended
case Sprites:
+ {
if (!m_spriteEngine) {
qWarning() << "ImageParticle: No sprite engine...";
//Sprite performance mode with static image is supported, but not advised
@@ -1318,16 +1734,19 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node)
return;
imageLoaded = true;
}
- m_material = SpriteMaterial::createMaterial();
+ m_material = new SpriteMaterial;
+ ImageMaterialData *state = getState(m_material);
if (imageLoaded)
- getState<ImageMaterialData>(m_material)->texture = QSGPlainTexture::fromImage(image);
- getState<ImageMaterialData>(m_material)->animSheetSize = QSizeF(image.size() / image.devicePixelRatioF());
+ state->texture = QSGPlainTexture::fromImage(image);
+ state->animSheetSize = QSizeF(image.size() / image.devicePixelRatioF());
if (m_spriteEngine)
m_spriteEngine->setCount(m_count);
+ }
Q_FALLTHROUGH();
case Tabled:
+ {
if (!m_material)
- m_material = TabledMaterial::createMaterial();
+ m_material = new TabledMaterial;
if (m_colorTable) {
if (m_colorTable->pix.isReady())
@@ -1354,21 +1773,29 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node)
colortable = QImage(1,1,QImage::Format_ARGB32_Premultiplied);
colortable.fill(Qt::white);
}
- getState<ImageMaterialData>(m_material)->colorTable = QSGPlainTexture::fromImage(colortable);
- fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->sizeTable, sizetable, UNIFORM_ARRAY_SIZE);
- fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->opacityTable, opacitytable, UNIFORM_ARRAY_SIZE);
+ ImageMaterialData *state = getState(m_material);
+ state->colorTable = QSGPlainTexture::fromImage(colortable);
+ fillUniformArrayFromImage(state->sizeTable, sizetable, UNIFORM_ARRAY_SIZE);
+ fillUniformArrayFromImage(state->opacityTable, opacitytable, UNIFORM_ARRAY_SIZE);
+ }
Q_FALLTHROUGH();
case Deformable:
+ {
if (!m_material)
- m_material = DeformableMaterial::createMaterial();
+ m_material = new DeformableMaterial;
+ }
Q_FALLTHROUGH();
case Colored:
+ {
if (!m_material)
- m_material = ColoredMaterial::createMaterial();
+ m_material = new ColoredMaterial;
+ }
Q_FALLTHROUGH();
default://Also Simple
+ {
if (!m_material)
- m_material = SimpleMaterial::createMaterial();
+ m_material = new SimpleMaterial;
+ ImageMaterialData *state = getState(m_material);
if (!imageLoaded) {
if (!m_image || !m_image->pix.isReady()) {
if (m_image)
@@ -1376,14 +1803,15 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node)
delete m_material;
return;
}
- //getState<ImageMaterialData>(m_material)->texture //TODO: Shouldn't this be better? But not crash?
+ //state->texture //TODO: Shouldn't this be better? But not crash?
// = QQuickItemPrivate::get(this)->sceneGraphContext()->textureForFactory(m_imagePix.textureFactory());
- getState<ImageMaterialData>(m_material)->texture = QSGPlainTexture::fromImage(m_image->pix.image());
+ state->texture = QSGPlainTexture::fromImage(m_image->pix.image());
}
- getState<ImageMaterialData>(m_material)->texture->setFiltering(QSGTexture::Linear);
- getState<ImageMaterialData>(m_material)->entry = (qreal) m_entryEffect;
+ state->texture->setFiltering(QSGTexture::Linear);
+ state->entry = (qreal) m_entryEffect;
m_material->setFlag(QSGMaterial::Blending | QSGMaterial::RequiresFullMatrix);
}
+ }
m_nodes.clear();
for (auto groupId : groupIds()) {
@@ -1416,14 +1844,23 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node)
node->setFlag(QSGNode::OwnsGeometry);
node->setGeometry(g);
if (perfLevel <= Colored){
- g->setDrawingMode(GL_POINTS);
- if (m_debugMode){
- GLfloat pointSizeRange[2];
- QOpenGLContext::currentContext()->functions()->glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
- qDebug() << "Using point sprites, GL_ALIASED_POINT_SIZE_RANGE " <<pointSizeRange[0] << ":" << pointSizeRange[1];
+ g->setDrawingMode(QSGGeometry::DrawPoints);
+ if (m_debugMode) {
+ if (m_rhi) {
+ qDebug("Using point sprites");
+ } else {
+#if QT_CONFIG(opengl)
+ GLfloat pointSizeRange[2];
+ QOpenGLContext::currentContext()->functions()->glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
+ qDebug() << "Using point sprites, GL_ALIASED_POINT_SIZE_RANGE " <<pointSizeRange[0] << ":" << pointSizeRange[1];
+#else
+ qDebug("Using point sprites");
+#endif
+ }
}
- }else
- g->setDrawingMode(GL_TRIANGLES);
+ } else {
+ g->setDrawingMode(QSGGeometry::DrawTriangles);
+ }
for (int p=0; p < count; ++p)
commit(groupId, p);//commit sets geometry for the node, has its own perfLevel switch
@@ -1464,16 +1901,34 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node)
update();
}
-static inline bool isOpenGL(QSGRenderContext *rc)
-{
- QSGRendererInterface *rif = rc->sceneGraphContext()->rendererInterface(rc);
- return !rif || rif->graphicsApi() == QSGRendererInterface::OpenGL;
-}
-
QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
{
- if (!node && !isOpenGL(QQuickItemPrivate::get(this)->sceneGraphRenderContext()))
- return nullptr;
+ if (!m_apiChecked || m_windowChanged) {
+ m_apiChecked = true;
+ m_windowChanged = false;
+
+ QSGRenderContext *rc = QQuickItemPrivate::get(this)->sceneGraphRenderContext();
+ QSGRendererInterface *rif = rc->sceneGraphContext()->rendererInterface(rc);
+ if (!rif)
+ return nullptr;
+
+ QSGRendererInterface::GraphicsApi api = rif->graphicsApi();
+ const bool isDirectOpenGL = api == QSGRendererInterface::OpenGL;
+ const bool isRhi = QSGRendererInterface::isApiRhiBased(api);
+
+ if (!node && !isDirectOpenGL && !isRhi)
+ return nullptr;
+
+ if (isRhi)
+ m_rhi = static_cast<QRhi *>(rif->getResource(m_window, QSGRendererInterface::RhiResource));
+ else
+ m_rhi = nullptr;
+
+ if (isRhi && !m_rhi) {
+ qWarning("Failed to query QRhi, particles disabled");
+ return nullptr;
+ }
+ }
if (m_pleaseReset){
if (node)
@@ -1541,7 +1996,7 @@ void QQuickImageParticle::prepareNextFrame(QSGNode **node)
case Colored:
case Simple:
default: //Also Simple
- getState<ImageMaterialData>(m_material)->timestamp = time;
+ getState(m_material)->timestamp = time;
break;
}
foreach (QSGGeometryNode* node, m_nodes)
@@ -1550,6 +2005,7 @@ void QQuickImageParticle::prepareNextFrame(QSGNode **node)
void QQuickImageParticle::spritesUpdate(qreal time)
{
+ ImageMaterialData *state = getState(m_material);
// Sprite progression handled CPU side, so as to have per-frame control.
for (auto groupId : groupIds()) {
for (QQuickParticleData* mainDatum : qAsConst(m_system->groupData[groupId]->data)) {
@@ -1587,7 +2043,7 @@ void QQuickImageParticle::spritesUpdate(qreal time)
}
if (m_spriteEngine->sprite(spriteIdx)->reverse())//### Store this in datum too?
frameAt = (datum->frameCount - 1) - frameAt;
- QSizeF sheetSize = getState<ImageMaterialData>(m_material)->animSheetSize;
+ QSizeF sheetSize = state->animSheetSize;
qreal y = datum->animY / sheetSize.height();
qreal w = datum->animWidth / sheetSize.width();
qreal h = datum->animHeight / sheetSize.height();
@@ -1686,6 +2142,7 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx)
writeTo->animHeight = m_spriteEngine->spriteHeight(spriteIdx);
}
} else {
+ ImageMaterialData *state = getState(m_material);
QQuickParticleData* writeTo = getShadowDatum(datum);
writeTo->animT = datum->t;
writeTo->frameCount = 1;
@@ -1694,8 +2151,8 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx)
writeTo->animIdx = 0;
writeTo->animT = 0;
writeTo->animX = writeTo->animY = 0;
- writeTo->animWidth = getState<ImageMaterialData>(m_material)->animSheetSize.width();
- writeTo->animHeight = getState<ImageMaterialData>(m_material)->animSheetSize.height();
+ writeTo->animWidth = state->animSheetSize.width();
+ writeTo->animHeight = state->animSheetSize.height();
}
Q_FALLTHROUGH();
case Tabled:
diff --git a/src/particles/qquickimageparticle_p.h b/src/particles/qquickimageparticle_p.h
index 95323c25a6..059cf67019 100644
--- a/src/particles/qquickimageparticle_p.h
+++ b/src/particles/qquickimageparticle_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef ULTRAPARTICLE_H
-#define ULTRAPARTICLE_H
+#ifndef QQUICKIMAGEPARTICLE_P_H
+#define QQUICKIMAGEPARTICLE_P_H
//
// W A R N I N G
@@ -50,21 +50,25 @@
//
// We mean it.
//
+
#include "qquickparticlepainter_p.h"
#include "qquickdirection_p.h"
#include <private/qquickpixmapcache_p.h>
#include <QQmlListProperty>
-#include <QtQuick/qsgsimplematerial.h>
#include <QtGui/qcolor.h>
+#include <QtQuick/qsgmaterial.h>
QT_BEGIN_NAMESPACE
class ImageMaterialData;
class QSGGeometryNode;
+class QSGMaterial;
class QQuickSprite;
class QQuickStochasticEngine;
+class QRhi;
+
struct SimpleVertex {
float x;
float y;
@@ -153,6 +157,12 @@ struct Vertices {
Vertex v4;
};
+class ImageMaterial : public QSGMaterial
+{
+public:
+ virtual ImageMaterialData *state() = 0;
+};
+
class QQuickImageParticle : public QQuickParticlePainter
{
Q_OBJECT
@@ -439,14 +449,17 @@ private:
}
}
- template<class MaterialData>
- static MaterialData* getState(QSGMaterial* m) {
- return static_cast<QSGSimpleMaterial<MaterialData> *>(m)->state();
+ ImageMaterialData *getState(QSGMaterial *m) {
+ return static_cast<ImageMaterial *>(m)->state();
}
+
EntryEffect m_entryEffect;
Status m_status;
int m_startedImageLoading;
+ QRhi *m_rhi;
+ bool m_apiChecked;
};
QT_END_NAMESPACE
-#endif // ULTRAPARTICLE_H
+
+#endif // QQUICKIMAGEPARTICLE_P_H
diff --git a/src/particles/qquickparticlepainter.cpp b/src/particles/qquickparticlepainter.cpp
index e762b3ae1d..78e11fafcf 100644
--- a/src/particles/qquickparticlepainter.cpp
+++ b/src/particles/qquickparticlepainter.cpp
@@ -70,6 +70,7 @@ QQuickParticlePainter::QQuickParticlePainter(QQuickItem *parent)
, m_count(0)
, m_pleaseReset(true)
, m_window(nullptr)
+ , m_windowChanged(false)
, m_groupIdsNeedRecalculation(false)
{
}
@@ -80,6 +81,7 @@ void QQuickParticlePainter::itemChange(ItemChange change, const ItemChangeData &
if (m_window)
disconnect(m_window, SIGNAL(sceneGraphInvalidated()), this, SLOT(sceneGraphInvalidated()));
m_window = data.window;
+ m_windowChanged = true;
if (m_window)
connect(m_window, SIGNAL(sceneGraphInvalidated()), this, SLOT(sceneGraphInvalidated()), Qt::DirectConnection);
}
diff --git a/src/particles/qquickparticlepainter_p.h b/src/particles/qquickparticlepainter_p.h
index ac14a18103..16fc6b6f45 100644
--- a/src/particles/qquickparticlepainter_p.h
+++ b/src/particles/qquickparticlepainter_p.h
@@ -141,6 +141,7 @@ protected:
QPointF m_systemOffset;
QQuickWindow *m_window;
+ bool m_windowChanged;
private: // methods
void recalculateGroupIds() const;
diff --git a/src/particles/shaders_ng/compile.bat b/src/particles/shaders_ng/compile.bat
new file mode 100755
index 0000000000..2376d5bf6d
--- /dev/null
+++ b/src/particles/shaders_ng/compile.bat
@@ -0,0 +1,53 @@
+:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+::
+:: Copyright (C) 2019 The Qt Company Ltd.
+:: Contact: https://www.qt.io/licensing/
+::
+:: This file is part of the QtQuick module of the Qt Toolkit.
+::
+:: $QT_BEGIN_LICENSE:LGPL$
+:: Commercial License Usage
+:: Licensees holding valid commercial Qt licenses may use this file in
+:: accordance with the commercial license agreement provided with the
+:: Software or, alternatively, in accordance with the terms contained in
+:: a written agreement between you and The Qt Company. For licensing terms
+:: and conditions see https://www.qt.io/terms-conditions. For further
+:: information use the contact form at https://www.qt.io/contact-us.
+::
+:: GNU Lesser General Public License Usage
+:: Alternatively, this file may be used under the terms of the GNU Lesser
+:: General Public License version 3 as published by the Free Software
+:: Foundation and appearing in the file LICENSE.LGPL3 included in the
+:: packaging of this file. Please review the following information to
+:: ensure the GNU Lesser General Public License version 3 requirements
+:: will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+::
+:: GNU General Public License Usage
+:: Alternatively, this file may be used under the terms of the GNU
+:: General Public License version 2.0 or (at your option) the GNU General
+:: Public license version 3 or any later version approved by the KDE Free
+:: Qt Foundation. The licenses are as published by the Free Software
+:: Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+:: included in the packaging of this file. Please review the following
+:: information to ensure the GNU General Public License requirements will
+:: be met: https://www.gnu.org/licenses/gpl-2.0.html and
+:: https://www.gnu.org/licenses/gpl-3.0.html.
+::
+:: $QT_END_LICENSE$
+::
+:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+qsb -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_simple.vert.qsb imageparticle.vert
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_simple.frag.qsb imageparticle.frag
+
+qsb -DTABLE -DDEFORM -DCOLOR -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_tabled.vert.qsb imageparticle.vert
+qsb -DTABLE -DDEFORM -DCOLOR --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_tabled.frag.qsb imageparticle.frag
+
+qsb -DDEFORM -DCOLOR -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_deformed.vert.qsb imageparticle.vert
+qsb -DDEFORM -DCOLOR --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_deformed.frag.qsb imageparticle.frag
+
+qsb -DSPRITE -DTABLE -DDEFORM -DCOLOR -b --zorder-loc 8 --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_sprite.vert.qsb imageparticle.vert
+qsb -DSPRITE -DTABLE -DDEFORM -DCOLOR --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_sprite.frag.qsb imageparticle.frag
+
+qsb -DCOLOR -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_colored.vert.qsb imageparticle.vert
+qsb -DCOLOR --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_colored.frag.qsb imageparticle.frag
diff --git a/src/particles/shaders_ng/imageparticle.frag b/src/particles/shaders_ng/imageparticle.frag
new file mode 100644
index 0000000000..cefb7d2d75
--- /dev/null
+++ b/src/particles/shaders_ng/imageparticle.frag
@@ -0,0 +1,55 @@
+#version 440
+
+#if defined(TABLE)
+layout(location = 0) in vec2 tt;
+#endif
+
+#if defined(SPRITE)
+layout(location = 1) in vec4 fTexS;
+#elif defined(DEFORM)
+layout(location = 1) in vec2 fTex;
+#endif
+
+#if defined(COLOR)
+layout(location = 2) in vec4 fColor;
+#else
+layout(location = 2) in float fFade;
+#endif
+
+layout(location = 0) out vec4 fragColor;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 matrix;
+ float opacity;
+ float entry;
+ float timestamp;
+ float sizetable[64];
+ float opacitytable[64];
+} ubuf;
+
+layout(binding = 1) uniform sampler2D _qt_texture;
+
+#if defined(TABLE) || defined(SPRITE)
+layout(binding = 2) uniform sampler2D colortable;
+#endif
+
+void main()
+{
+#if defined(SPRITE)
+ fragColor = mix(texture(_qt_texture, fTexS.xy), texture(_qt_texture, fTexS.zw), tt.y)
+ * fColor
+ * texture(colortable, tt)
+ * ubuf.opacity;
+#elif defined(TABLE)
+ fragColor = texture(_qt_texture, fTex)
+ * fColor
+ * texture(colortable, tt)
+ * ubuf.opacity;
+#elif defined(DEFORM)
+ fragColor = texture(_qt_texture, fTex) * fColor * ubuf.opacity;
+#elif defined(COLOR)
+ fragColor = texture(_qt_texture, gl_PointCoord) * fColor * ubuf.opacity;
+#else
+ fragColor = texture(_qt_texture, gl_PointCoord) * fFade * ubuf.opacity;
+#endif
+}
diff --git a/src/particles/shaders_ng/imageparticle.vert b/src/particles/shaders_ng/imageparticle.vert
new file mode 100644
index 0000000000..870139452b
--- /dev/null
+++ b/src/particles/shaders_ng/imageparticle.vert
@@ -0,0 +1,145 @@
+#version 440
+
+layout(location = 1) in vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize
+layout(location = 2) in vec4 vVec; // x,y = constant velocity, z,w = acceleration
+
+#if defined(DEFORM)
+layout(location = 0) in vec4 vPosTex;
+#else
+layout(location = 0) in vec2 vPos;
+#endif
+
+#if defined(COLOR)
+layout(location = 3) in vec4 vColor;
+#endif
+
+#if defined(DEFORM)
+layout(location = 4) in vec4 vDeformVec; // x,y x unit vector; z,w = y unit vector
+layout(location = 5) in vec3 vRotation; // x = radians of rotation, y = rotation velocity, z = bool autoRotate
+#endif
+
+#if defined(SPRITE)
+layout(location = 6) in vec3 vAnimData; // w,h(premultiplied of anim), interpolation progress
+layout(location = 7) in vec4 vAnimPos; // x,y, x,y (two frames for interpolation)
+#endif
+
+#if defined(TABLE)
+layout(location = 0) out vec2 tt; //y is progress if Sprite mode
+#endif
+
+#if defined(SPRITE)
+layout(location = 1) out vec4 fTexS;
+#elif defined(DEFORM)
+layout(location = 1) out vec2 fTex;
+#endif
+
+#if defined(COLOR)
+layout(location = 2) out vec4 fColor;
+#else
+layout(location = 2) out float fFade;
+#endif
+
+layout(std140, binding = 0) uniform buf {
+ mat4 matrix;
+ float opacity;
+ float entry;
+ float timestamp;
+ float sizetable[64];
+ float opacitytable[64];
+} ubuf;
+
+out gl_PerVertex { vec4 gl_Position; float gl_PointSize; };
+
+void main()
+{
+ float t = (ubuf.timestamp - vData.x) / vData.y;
+ if (t < 0. || t > 1.) {
+#if defined(DEFORM)
+ gl_Position = ubuf.matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.);
+#else
+ gl_PointSize = 0.;
+#endif
+ } else {
+#if defined(SPRITE)
+ tt.y = vAnimData.z;
+
+ // Calculate frame location in texture
+ fTexS.xy = vAnimPos.xy + vPosTex.zw * vAnimData.xy;
+
+ // Next frame is also passed, for interpolation
+ fTexS.zw = vAnimPos.zw + vPosTex.zw * vAnimData.xy;
+
+#elif defined(DEFORM)
+ fTex = vPosTex.zw;
+#endif
+ float currentSize = mix(vData.z, vData.w, t * t);
+ float fade = 1.;
+ float fadeIn = min(t * 10., 1.);
+ float fadeOut = 1. - clamp((t - 0.75) * 4.,0., 1.);
+
+#if defined(TABLE)
+ currentSize = currentSize * ubuf.sizetable[int(floor(t*64.))];
+ fade = fade * ubuf.opacitytable[int(floor(t*64.))];
+#endif
+
+ if (ubuf.entry == 1.)
+ fade = fade * fadeIn * fadeOut;
+ else if (ubuf.entry == 2.)
+ currentSize = currentSize * fadeIn * fadeOut;
+
+ if (currentSize <= 0.) {
+#if defined(DEFORM)
+ gl_Position = ubuf.matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.);
+#else
+ gl_PointSize = 0.;
+#endif
+ } else {
+ if (currentSize < 3.) // Sizes too small look jittery as they move
+ currentSize = 3.;
+
+ vec2 pos;
+#if defined(DEFORM)
+ float rotation = vRotation.x + vRotation.y * t * vData.y;
+ if (vRotation.z == 1.0) {
+ vec2 curVel = vVec.zw * t * vData.y + vVec.xy;
+ if (length(curVel) > 0.)
+ rotation += atan(curVel.y, curVel.x);
+ }
+ vec2 trigCalcs = vec2(cos(rotation), sin(rotation));
+ vec4 deform = vDeformVec * currentSize * (vPosTex.zzww - 0.5);
+ vec4 rotatedDeform = deform.xxzz * trigCalcs.xyxy;
+ rotatedDeform = rotatedDeform + (deform.yyww * trigCalcs.yxyx * vec4(-1.,1.,-1.,1.));
+ /* The readable version:
+ vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5);
+ vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5);
+ vec2 xRotatedDeform;
+ xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y;
+ xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y;
+ vec2 yRotatedDeform;
+ yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y;
+ yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y;
+ */
+ pos = vPosTex.xy
+ + rotatedDeform.xy
+ + rotatedDeform.zw
+ + vVec.xy * t * vData.y // apply velocity
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration
+#else
+ pos = vPos
+ + vVec.xy * t * vData.y // apply velocity vector..
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.);
+ gl_PointSize = currentSize;
+#endif
+ gl_Position = ubuf.matrix * vec4(pos.x, pos.y, 0, 1);
+
+#if defined(COLOR)
+ fColor = vColor * fade;
+#else
+ fFade = fade;
+#endif
+#if defined(TABLE)
+ tt.x = t;
+#endif
+ }
+ }
+}
diff --git a/src/particles/shaders_ng/imageparticle_colored.frag.qsb b/src/particles/shaders_ng/imageparticle_colored.frag.qsb
new file mode 100644
index 0000000000..7ae640d224
--- /dev/null
+++ b/src/particles/shaders_ng/imageparticle_colored.frag.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_colored.vert.qsb b/src/particles/shaders_ng/imageparticle_colored.vert.qsb
new file mode 100644
index 0000000000..0e2938b72c
--- /dev/null
+++ b/src/particles/shaders_ng/imageparticle_colored.vert.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_deformed.frag.qsb b/src/particles/shaders_ng/imageparticle_deformed.frag.qsb
new file mode 100644
index 0000000000..fa9d9d35bb
--- /dev/null
+++ b/src/particles/shaders_ng/imageparticle_deformed.frag.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_deformed.vert.qsb b/src/particles/shaders_ng/imageparticle_deformed.vert.qsb
new file mode 100644
index 0000000000..65092d5b26
--- /dev/null
+++ b/src/particles/shaders_ng/imageparticle_deformed.vert.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_simple.frag.qsb b/src/particles/shaders_ng/imageparticle_simple.frag.qsb
new file mode 100644
index 0000000000..a5874cba24
--- /dev/null
+++ b/src/particles/shaders_ng/imageparticle_simple.frag.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_simple.vert.qsb b/src/particles/shaders_ng/imageparticle_simple.vert.qsb
new file mode 100644
index 0000000000..da815d7e19
--- /dev/null
+++ b/src/particles/shaders_ng/imageparticle_simple.vert.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_sprite.frag.qsb b/src/particles/shaders_ng/imageparticle_sprite.frag.qsb
new file mode 100644
index 0000000000..778550344b
--- /dev/null
+++ b/src/particles/shaders_ng/imageparticle_sprite.frag.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_sprite.vert.qsb b/src/particles/shaders_ng/imageparticle_sprite.vert.qsb
new file mode 100644
index 0000000000..45b21ace8a
--- /dev/null
+++ b/src/particles/shaders_ng/imageparticle_sprite.vert.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_tabled.frag.qsb b/src/particles/shaders_ng/imageparticle_tabled.frag.qsb
new file mode 100644
index 0000000000..c5dcc2c68f
--- /dev/null
+++ b/src/particles/shaders_ng/imageparticle_tabled.frag.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_tabled.vert.qsb b/src/particles/shaders_ng/imageparticle_tabled.vert.qsb
new file mode 100644
index 0000000000..ea42607570
--- /dev/null
+++ b/src/particles/shaders_ng/imageparticle_tabled.vert.qsb
Binary files differ
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop.cpp
index 120a84566f..f505df1e5a 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop.cpp
@@ -121,10 +121,6 @@ const QEvent::Type WM_Obscure = QEvent::Type(QEvent::User + 1);
// Passed from the RL to RT when GUI has been locked, waiting for sync.
const QEvent::Type WM_RequestSync = QEvent::Type(QEvent::User + 2);
-// Passed by the RT to itself to trigger another render pass. This is typically
-// a result of QQuickWindow::update().
-const QEvent::Type WM_RequestRepaint = QEvent::Type(QEvent::User + 3);
-
// Passed by the RL to the RT to maybe release resource if no windows are
// rendering.
const QEvent::Type WM_TryRelease = QEvent::Type(QEvent::User + 4);
@@ -436,14 +432,6 @@ bool QSGD3D12RenderThread::event(QEvent *e)
return true;
}
- case WM_RequestRepaint:
- if (Q_UNLIKELY(debug_loop()))
- qDebug("RT - WM_RequestPaint");
- // When GUI posts this event, it is followed by a polishAndSync, so we
- // must not exit the event loop yet.
- pendingUpdate |= RepaintRequest;
- break;
-
default:
break;
}
diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc
index 9c106558fd..c71d18418a 100644
--- a/src/qml/doc/src/qmlfunctions.qdoc
+++ b/src/qml/doc/src/qmlfunctions.qdoc
@@ -274,6 +274,16 @@
*/
/*!
+ \fn int qmlRegisterAnonymousType(const char *uri, int versionMajor)
+
+ This template function registers the C++ type in the QML system. Instances of this type cannot be created from the QML system.
+
+ Use this function when the type will not be referenced by name. Use \a uri and \a versionMajor to indicate to which module the type belongs.
+
+ \sa {Choosing the Correct Integration Method Between C++ and QML}
+*/
+
+/*!
\fn int qmlRegisterType()
\relates QQmlEngine
\overload
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index 6c9760e472..8ac7633ae0 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -1246,8 +1246,13 @@ UiObjectMember: T_DEFAULT T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlId
sym(1).Node = node;
} break;
./
+OptionalSemicolon: | Semicolon;
+/.
+/* we need OptionalSemicolon because UiScriptStatement might already parse the last semicolon
+ and then we would miss a semicolon (see tests/auto/quick/qquickvisualdatamodel/data/objectlist.qml)*/
+ ./
-UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement;
+UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3), sym(5).Statement);
@@ -1259,7 +1264,7 @@ UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatemen
} break;
./
-UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement;
+UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4), sym(6).Statement);
@@ -1273,7 +1278,7 @@ UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScr
} break;
./
-UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement;
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4), sym(6).Statement);
@@ -1287,7 +1292,7 @@ UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScri
} break;
./
-UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET;
+UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6));
@@ -1313,7 +1318,7 @@ UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T
} break;
./
-UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET;
+UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7));
@@ -1341,7 +1346,7 @@ UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlI
} break;
./
-UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer;
+UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3));
@@ -1364,7 +1369,7 @@ UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatem
} break;
./
-UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer;
+UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4));
diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp
index 700c191499..b63b2191b9 100644
--- a/src/qml/parser/qqmljsast.cpp
+++ b/src/qml/parser/qqmljsast.cpp
@@ -238,12 +238,11 @@ void StringLiteral::accept0(Visitor *visitor)
void TemplateLiteral::accept0(Visitor *visitor)
{
- if (visitor->visit(this)) {
- if (next)
- accept(next, visitor);
+ bool accepted = true;
+ for (TemplateLiteral *it = this; it && accepted; it = it->next) {
+ accepted = visitor->visit(it);
+ visitor->endVisit(it);
}
-
- visitor->endVisit(this);
}
void NumericLiteral::accept0(Visitor *visitor)
@@ -1015,13 +1014,13 @@ BoundNames FormalParameterList::boundNames() const
void FormalParameterList::accept0(Visitor *visitor)
{
- if (visitor->visit(this)) {
- accept(element, visitor);
- if (next)
- accept(next, visitor);
+ bool accepted = true;
+ for (FormalParameterList *it = this; it && accepted; it = it->next) {
+ accepted = visitor->visit(it);
+ if (accepted)
+ accept(it->element, visitor);
+ visitor->endVisit(it);
}
-
- visitor->endVisit(this);
}
FormalParameterList *FormalParameterList::finish(QQmlJS::MemoryPool *pool)
@@ -1321,12 +1320,14 @@ void UiPragma::accept0(Visitor *visitor)
void UiHeaderItemList::accept0(Visitor *visitor)
{
- if (visitor->visit(this)) {
- accept(headerItem, visitor);
- accept(next, visitor);
- }
+ bool accepted = true;
+ for (UiHeaderItemList *it = this; it && accepted; it = it->next) {
+ accepted = visitor->visit(it);
+ if (accepted)
+ accept(it->headerItem, visitor);
- visitor->endVisit(this);
+ visitor->endVisit(it);
+ }
}
@@ -1391,14 +1392,15 @@ void PatternElement::boundNames(BoundNames *names)
void PatternElementList::accept0(Visitor *visitor)
{
- if (visitor->visit(this)) {
- accept(elision, visitor);
- accept(element, visitor);
- if (next)
- accept(next, visitor);
+ bool accepted = true;
+ for (PatternElementList *it = this; it && accepted; it = it->next) {
+ accepted = visitor->visit(it);
+ if (accepted) {
+ accept(it->elision, visitor);
+ accept(it->element, visitor);
+ }
+ visitor->endVisit(it);
}
-
- visitor->endVisit(this);
}
void PatternElementList::boundNames(BoundNames *names)
@@ -1428,13 +1430,13 @@ void PatternProperty::boundNames(BoundNames *names)
void PatternPropertyList::accept0(Visitor *visitor)
{
- if (visitor->visit(this)) {
- accept(property, visitor);
- if (next)
- accept(next, visitor);
+ bool accepted = true;
+ for (PatternPropertyList *it = this; it && accepted; it = it->next) {
+ accepted = visitor->visit(it);
+ if (accepted)
+ accept(it->property, visitor);
+ visitor->endVisit(it);
}
-
- visitor->endVisit(this);
}
void PatternPropertyList::boundNames(BoundNames *names)
@@ -1479,13 +1481,14 @@ void ClassDeclaration::accept0(Visitor *visitor)
void ClassElementList::accept0(Visitor *visitor)
{
- if (visitor->visit(this)) {
- accept(property, visitor);
- if (next)
- accept(next, visitor);
- }
+ bool accepted = true;
+ for (ClassElementList *it = this; it && accepted; it = it->next) {
+ accepted = visitor->visit(it);
+ if (accepted)
+ accept(it->property, visitor);
- visitor->endVisit(this);
+ visitor->endVisit(it);
+ }
}
ClassElementList *ClassElementList::finish()
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri
index 08591b5237..2e9c6f3de6 100644
--- a/src/qml/qml/qml.pri
+++ b/src/qml/qml/qml.pri
@@ -186,5 +186,7 @@ qtConfig(qml-network) {
$$PWD/qqmltypeloadernetworkreplyproxy.cpp
}
+android: DEFINES += LIBS_SUFFIX='\\"_$${QT_ARCH}.so\\"'
+
include(ftw/ftw.pri)
include(v8/v8.pri)
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index bfd1c88b28..a93b012c70 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -102,7 +102,7 @@ class QQmlPropertyValueInterceptor;
void Q_QML_EXPORT qmlClearTypeRegistrations();
template<typename T>
-int qmlRegisterType()
+int qmlRegisterAnonymousType(const char *uri, int versionMajor=1)
{
QML_GETTYPENAMES
@@ -115,7 +115,7 @@ int qmlRegisterType()
nullptr,
QString(),
- nullptr, 0, 0, nullptr, &T::staticMetaObject,
+ uri, versionMajor, 0, nullptr, &T::staticMetaObject,
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
@@ -133,6 +133,12 @@ int qmlRegisterType()
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
}
+template<typename T>
+QT_DEPRECATED_VERSION_X_5_14("Use qmlRegisterAnonymousType instead") int qmlRegisterType()
+{
+ return qmlRegisterAnonymousType<T>("");
+}
+
int Q_QML_EXPORT qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message);
template<typename T>
diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp
index e93cfcadb9..d04a89b514 100644
--- a/src/qml/qml/qqmlapplicationengine.cpp
+++ b/src/qml/qml/qqmlapplicationengine.cpp
@@ -131,7 +131,7 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c)
q->objectCreated(nullptr, c->url());
break;
case QQmlComponent::Ready: {
- auto newObj = c->create();
+ auto newObj = initialProperties.empty() ? c->create() : c->createWithInitialProperties(initialProperties);
objects << newObj;
QObject::connect(newObj, &QObject::destroyed, q, [&](QObject *obj) { objects.removeAll(obj); });
q->objectCreated(objects.constLast(), c->url());
@@ -279,6 +279,22 @@ void QQmlApplicationEngine::load(const QString &filePath)
}
/*!
+ Sets the initial properties with which the QML component gets initialized after
+ it gets loaded.
+
+
+ \sa QQmlComponent::setInitialProperties
+ \sa QQmlApplicationEngine::load
+ \sa QQmlApplicationEngine::loadData
+ \since 5.14
+*/
+void QQmlApplicationEngine::setInitialProperties(const QVariantMap &initialProperties)
+{
+ Q_D(QQmlApplicationEngine);
+ d->initialProperties = initialProperties;
+}
+
+/*!
Loads the QML given in \a data. The object tree defined by \a data is
instantiated immediately.
diff --git a/src/qml/qml/qqmlapplicationengine.h b/src/qml/qml/qqmlapplicationengine.h
index bb5d6b5d68..2b4de91154 100644
--- a/src/qml/qml/qqmlapplicationengine.h
+++ b/src/qml/qml/qqmlapplicationengine.h
@@ -66,6 +66,7 @@ public:
public Q_SLOTS:
void load(const QUrl &url);
void load(const QString &filePath);
+ void setInitialProperties(const QVariantMap &initialProperties);
void loadData(const QByteArray &data, const QUrl &url = QUrl());
Q_SIGNALS:
diff --git a/src/qml/qml/qqmlapplicationengine_p.h b/src/qml/qml/qqmlapplicationengine_p.h
index 7a341847bd..1279e400e8 100644
--- a/src/qml/qml/qqmlapplicationengine_p.h
+++ b/src/qml/qml/qqmlapplicationengine_p.h
@@ -73,6 +73,7 @@ public:
void loadTranslations(const QUrl &rootFile);
void finishLoad(QQmlComponent *component);
QList<QObject *> objects;
+ QVariantMap initialProperties;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index fefe2bc685..ed8c41a582 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -350,6 +350,32 @@ void QQmlComponentPrivate::clear()
compilationUnit = nullptr;
}
+QObject *QQmlComponentPrivate::doBeginCreate(QQmlComponent *q, QQmlContext *context)
+{
+ if (!engine) {
+ // ###Qt6: In Qt 6, it should be impossible for users to create a QQmlComponent without an engine, and we can remove this check
+ qWarning("QQmlComponent: Must provide an engine before calling create");
+ return nullptr;
+ }
+ if (!context)
+ context = engine->rootContext();
+ return q->beginCreate(context);
+}
+
+bool QQmlComponentPrivate::setInitialProperty(QObject *component, const QString& name, const QVariant &value)
+{
+ QQmlProperty prop(component, name);
+ auto privProp = QQmlPropertyPrivate::get(prop);
+ if (!prop.isValid() || !privProp->writeValueProperty(value, nullptr)) {
+ QQmlError error{};
+ error.setUrl(url);
+ error.setDescription(QLatin1String("Could not set property %1").arg(name));
+ state.errors.push_back(error);
+ return false;
+ } else
+ return true;
+}
+
/*!
\internal
*/
@@ -780,18 +806,28 @@ QObject *QQmlComponent::create(QQmlContext *context)
{
Q_D(QQmlComponent);
- if (!d->engine) {
- // ###Qt6: In Qt 6, it should be impossible for users to create a QQmlComponent without an engine, and we can remove this check
- qWarning("QQmlComponent: Must provide an engine before calling create");
- return nullptr;
- }
+ QObject *rv = d->doBeginCreate(this, context);
+ if (rv)
+ completeCreate();
+ return rv;
+}
- if (!context)
- context = d->engine->rootContext();
+/*!
+ Create an object instance of this component, and initialize its toplevel properties according to initalPropertyValues.
- QObject *rv = beginCreate(context);
- if (rv)
+
+ \sa QQmlComponent::create
+ \since 5.14
+*/
+QObject *QQmlComponent::createWithInitialProperties(const QVariantMap& initialProperties, QQmlContext *context)
+{
+ Q_D(QQmlComponent);
+
+ QObject *rv = d->doBeginCreate(this, context);
+ if (rv) {
+ setInitialProperties(rv, initialProperties);
completeCreate();
+ }
return rv;
}
@@ -1067,6 +1103,26 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
enginePriv->incubate(incubator, forContextData);
}
+/*!
+ Set toplevel properties of the component.
+
+
+ This method provides advanced control over component instance creation.
+ In general, programmers should use
+ \l QQmlComponent::createWithInitialProperties to create a component.
+
+ Use this method after beginCreate and before completeCreate has been called.
+ If a provided property does not exist, a warning is issued.
+
+ \since 5.14
+*/
+void QQmlComponent::setInitialProperties(QObject *component, const QVariantMap &properties)
+{
+ Q_D(QQmlComponent);
+ for (auto it = properties.constBegin(); it != properties.constEnd(); ++it)
+ d->setInitialProperty(component, it.key(), it.value());
+}
+
/*
This is essentially a copy of QQmlComponent::create(); except it takes the QQmlContextData
arguments instead of QQmlContext which means we don't have to construct the rather weighty
diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h
index 39b6d4526f..f259c99b08 100644
--- a/src/qml/qml/qqmlcomponent.h
+++ b/src/qml/qml/qqmlcomponent.h
@@ -100,6 +100,8 @@ public:
QUrl url() const;
virtual QObject *create(QQmlContext *context = nullptr);
+ QObject *createWithInitialProperties(const QVariantMap& initialProperties, QQmlContext *context = nullptr);
+ void setInitialProperties(QObject *component, const QVariantMap &properties);
virtual QObject *beginCreate(QQmlContext *);
virtual void completeCreate();
diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h
index 9a967501c9..2170646b89 100644
--- a/src/qml/qml/qqmlcomponent_p.h
+++ b/src/qml/qml/qqmlcomponent_p.h
@@ -143,6 +143,9 @@ public:
static QQmlComponentPrivate *get(QQmlComponent *c) {
return static_cast<QQmlComponentPrivate *>(QObjectPrivate::get(c));
}
+
+ QObject *doBeginCreate(QQmlComponent *q, QQmlContext *context);
+ bool setInitialProperty(QObject *component, const QString &name, const QVariant& value);
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 8bf660d2ec..5fb5d73341 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -206,14 +206,18 @@ void QQmlEnginePrivate::defineModule()
qmlRegisterType<QQmlBind>(uri, 2, 0, "Binding");
qmlRegisterType<QQmlBind, 8>(uri, 2, 8, "Binding"); // Only available in >= 2.8
qmlRegisterType<QQmlBind, 14>(uri, 2, 14, "Binding");
+
+ // TODO: We won't need Connections to be a custom type anymore once we can drop the
+ // automatic signal handler inference from undeclared properties.
qmlRegisterCustomType<QQmlConnections>(uri, 2, 0, "Connections", new QQmlConnectionsParser);
- qmlRegisterCustomType<QQmlConnections, 1>(uri, 2, 3, "Connections", new QQmlConnectionsParser); // Only available in QtQml >= 2.3
+ qmlRegisterCustomType<QQmlConnections, 3>(uri, 2, 3, "Connections", new QQmlConnectionsParser); // Only available in QtQml >= 2.3
+
#if QT_CONFIG(qml_animation)
qmlRegisterType<QQmlTimer>(uri, 2, 0, "Timer");
#endif
qmlRegisterType<QQmlLoggingCategory>(uri, 2, 8, "LoggingCategory"); // Only available in >= 2.8
- qmlRegisterType<QQmlLoggingCategory, 1>(uri, 2, 12, "LoggingCategory"); // Only available in >= 2.12
+ qmlRegisterType<QQmlLoggingCategory, 12>(uri, 2, 12, "LoggingCategory"); // Only available in >= 2.12
#if QT_CONFIG(qml_locale)
qmlRegisterUncreatableType<QQmlLocale>(uri, 2, 2, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
@@ -796,11 +800,12 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
QMetaMethod m = QMetaObjectPrivate::signal(object->metaObject(), index);
QList<QByteArray> parameterTypes = m.parameterTypes();
- int *types = (int *)malloc((parameterTypes.count() + 1) * sizeof(int));
- void **args = (void **) malloc((parameterTypes.count() + 1) *sizeof(void *));
+ QScopedPointer<QMetaCallEvent> ev(new QMetaCallEvent(m.methodIndex(), 0, nullptr,
+ object, index,
+ parameterTypes.count() + 1));
- types[0] = 0; // return type
- args[0] = nullptr; // return value
+ void **args = ev->args();
+ int *types = ev->types();
for (int ii = 0; ii < parameterTypes.count(); ++ii) {
const QByteArray &typeName = parameterTypes.at(ii);
@@ -813,21 +818,16 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
qWarning("QObject::connect: Cannot queue arguments of type '%s'\n"
"(Make sure '%s' is registered using qRegisterMetaType().)",
typeName.constData(), typeName.constData());
- free(types);
- free(args);
return;
}
args[ii + 1] = QMetaType::create(types[ii + 1], a[ii + 1]);
}
- QMetaCallEvent *ev = new QMetaCallEvent(m.methodIndex(), 0, nullptr, object, index,
- parameterTypes.count() + 1, types, args);
-
QQmlThreadNotifierProxyObject *mpo = new QQmlThreadNotifierProxyObject;
mpo->target = object;
mpo->moveToThread(QObjectPrivate::get(object)->threadData->thread.loadAcquire());
- QCoreApplication::postEvent(mpo, ev);
+ QCoreApplication::postEvent(mpo, ev.take());
} else {
QQmlNotifierEndpoint *ep = ddata->notify(index);
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 7c9c0da01a..31a7004407 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -1852,9 +1852,15 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader,
QLatin1String(".so"),
QLatin1String(".bundle")
};
-# else // Unix
+#else // Unix
static const QString prefix = QLatin1String("lib");
- static const QStringList suffixes = { QLatin1String(".so") };
+ static const QStringList suffixes = {
+# if defined(Q_OS_ANDROID)
+ QStringLiteral(LIBS_SUFFIX),
+# endif
+ QLatin1String(".so")
+
+ };
#endif
return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName, suffixes, prefix);
diff --git a/src/qml/qml/qqmlloggingcategory_p.h b/src/qml/qml/qqmlloggingcategory_p.h
index ece06e04b4..ee5d9af2e7 100644
--- a/src/qml/qml/qqmlloggingcategory_p.h
+++ b/src/qml/qml/qqmlloggingcategory_p.h
@@ -65,7 +65,7 @@ class QQmlLoggingCategory : public QObject, public QQmlParserStatus
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QString name READ name WRITE setName)
- Q_PROPERTY(DefaultLogLevel defaultLogLevel READ defaultLogLevel WRITE setDefaultLogLevel REVISION 1)
+ Q_PROPERTY(DefaultLogLevel defaultLogLevel READ defaultLogLevel WRITE setDefaultLogLevel REVISION 12)
public:
enum DefaultLogLevel {
diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp
index 71964aca64..7dbcbe986b 100644
--- a/src/qml/qml/qqmlpropertyvalidator.cpp
+++ b/src/qml/qml/qqmlpropertyvalidator.cpp
@@ -711,21 +711,25 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPrope
// Using -1 for the minor version ensures that we get the raw metaObject.
QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(property->propType(), -1);
- // Will be true if the assigned type inherits propertyMetaObject
- bool isAssignable = false;
- // Determine isAssignable value
if (propertyMetaObject) {
+ // Will be true if the assigned type inherits propertyMetaObject
+ // Determine isAssignable value
+ bool isAssignable = false;
QQmlPropertyCache *c = propertyCaches.at(binding->value.objectIndex);
while (c && !isAssignable) {
isAssignable |= c == propertyMetaObject;
c = c->parent();
}
- }
- if (!isAssignable) {
- return qQmlCompileError(binding->valueLocation, tr("Cannot assign object of type \"%1\" to property of type \"%2\" as the former is neither the same as the latter nor a sub-class of it.")
- .arg(stringAt(compilationUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex)).arg(QLatin1String(QMetaType::typeName(property->propType()))));
+ if (!isAssignable) {
+ return qQmlCompileError(binding->valueLocation, tr("Cannot assign object of type \"%1\" to property of type \"%2\" as the former is neither the same as the latter nor a sub-class of it.")
+ .arg(stringAt(compilationUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex)).arg(QLatin1String(QMetaType::typeName(property->propType()))));
+ }
+ } else {
+ return qQmlCompileError(binding->valueLocation, tr("Cannot assign to property of unknown type \"%1\".")
+ .arg(QLatin1String(QMetaType::typeName(property->propType()))));
}
+
}
return noError;
}
diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp
index 88f7b69dc2..2225191a9d 100644
--- a/src/qml/qml/qqmlvaluetype.cpp
+++ b/src/qml/qml/qqmlvaluetype.cpp
@@ -122,8 +122,10 @@ const QMetaObject *QQmlValueTypeFactoryImpl::metaObjectForMetaType(int t)
return &QQmlRectValueType::staticMetaObject;
case QVariant::RectF:
return &QQmlRectFValueType::staticMetaObject;
+#if QT_CONFIG(easingcurve)
case QVariant::EasingCurve:
return &QQmlEasingValueType::staticMetaObject;
+#endif
#if QT_CONFIG(qml_itemmodel)
case QVariant::ModelIndex:
return &QQmlModelIndexValueType::staticMetaObject;
@@ -201,7 +203,9 @@ const QMetaObject *QQmlValueTypeFactory::metaObjectForMetaType(int type)
void QQmlValueTypeFactory::registerValueTypes(const char *uri, int versionMajor, int versionMinor)
{
+#if QT_CONFIG(easingcurve)
qmlRegisterValueTypeEnums<QQmlEasingValueType>(uri, versionMajor, versionMinor, "Easing");
+#endif
}
QQmlValueType::QQmlValueType(int typeId, const QMetaObject *gadgetMetaObject)
@@ -489,6 +493,7 @@ int QQmlRectValueType::bottom() const
return v.bottom();
}
+#if QT_CONFIG(easingcurve)
QQmlEasingValueType::Type QQmlEasingValueType::type() const
{
return (QQmlEasingValueType::Type)v.type();
@@ -572,6 +577,8 @@ QVariantList QQmlEasingValueType::bezierCurve() const
rv << QVariant(point.x()) << QVariant(point.y());
return rv;
}
+#endif // easingcurve
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h
index 89f1b71d61..75150b3f32 100644
--- a/src/qml/qml/qqmlvaluetype_p.h
+++ b/src/qml/qml/qqmlvaluetype_p.h
@@ -58,7 +58,9 @@
#include <QtCore/qobject.h>
#include <QtCore/qrect.h>
+#if QT_CONFIG(easingcurve)
#include <QtCore/qeasingcurve.h>
+#endif
#include <QtCore/qvariant.h>
QT_BEGIN_NAMESPACE
@@ -210,6 +212,7 @@ public:
int bottom() const;
};
+#if QT_CONFIG(easingcurve)
struct QQmlEasingValueType
{
QEasingCurve v;
@@ -260,6 +263,7 @@ public:
void setBezierCurve(const QVariantList &);
QVariantList bezierCurve() const;
};
+#endif
template<typename T>
int qmlRegisterValueTypeEnums(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp
index 4b60108597..861243987f 100644
--- a/src/qml/types/qqmlbind.cpp
+++ b/src/qml/types/qqmlbind.cpp
@@ -357,7 +357,7 @@ void QQmlBind::setDelayed(bool delayed)
\li Binding.RestoreValue The original value is restored if it was a plain
value rather than a binding.
\li Binding.RestoreBindingOrValue The original value is always restored.
- \list
+ \endlist
The default value is Binding.RestoreBinding.
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index 8ec754a9df..1e801641e5 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -44,6 +44,7 @@
#include <private/qqmlboundsignal_p.h>
#include <qqmlcontext.h>
#include <private/qqmlcontext_p.h>
+#include <private/qqmlvmemetaobject_p.h>
#include <qqmlinfo.h>
#include <QtCore/qdebug.h>
@@ -105,7 +106,7 @@ public:
\qml
MouseArea {
Connections {
- onClicked: foo(parameters)
+ function onClicked(mouse) { foo(mouse) }
}
}
\endqml
@@ -122,7 +123,7 @@ public:
\qml
Connections {
target: area
- onClicked: foo(parameters)
+ function onClicked(mouse) { foo(mouse) }
}
\endqml
@@ -270,8 +271,76 @@ void QQmlConnections::connectSignals()
if (!d->componentcomplete || (d->targetSet && !target()))
return;
- if (d->bindings.isEmpty())
+ if (d->bindings.isEmpty()) {
+ connectSignalsToMethods();
+ } else {
+#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
+ qmlWarning(this) << tr("Implicitly defined onFoo properties in Connections are deprecated. "
+ "Use this syntax instead: function onFoo(<arguments>) { ... }");
+#endif
+ connectSignalsToBindings();
+ }
+}
+
+void QQmlConnections::connectSignalsToMethods()
+{
+ Q_D(QQmlConnections);
+
+ QObject *target = this->target();
+ QQmlData *ddata = QQmlData::get(this);
+ if (!ddata)
return;
+
+ QV4::ExecutionEngine *engine = ddata->context->engine->handle();
+
+ QQmlContextData *ctxtdata = ddata->outerContext;
+ for (int i = ddata->propertyCache->methodOffset(),
+ end = ddata->propertyCache->methodOffset() + ddata->propertyCache->methodCount();
+ i < end;
+ ++i) {
+
+ QQmlPropertyData *handler = ddata->propertyCache->method(i);
+ if (!handler || !handler->isVMEFunction())
+ continue;
+
+ const QString propName = handler->name(this);
+
+ QQmlProperty prop(target, propName);
+ if (prop.isValid() && (prop.type() & QQmlProperty::SignalProperty)) {
+ int signalIndex = QQmlPropertyPrivate::get(prop)->signalIndex();
+ auto *signal = new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this));
+ signal->setEnabled(d->enabled);
+
+ QV4::Scope scope(engine);
+ QV4::ScopedContext global(scope, engine->rootContext());
+
+ QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(this);
+ Q_ASSERT(vmeMetaObject); // the fact we found the property above should guarentee this
+
+ QV4::ScopedFunctionObject method(scope, vmeMetaObject->vmeMethod(handler->coreIndex()));
+
+ QQmlBoundSignalExpression *expression =
+ ctxtdata ? new QQmlBoundSignalExpression(
+ target, signalIndex, ctxtdata, this,
+ method->as<QV4::FunctionObject>()->function())
+ : nullptr;
+
+ signal->takeExpression(expression);
+ d->boundsignals += signal;
+ } else if (!d->ignoreUnknownSignals
+ && propName.startsWith(QLatin1String("on")) && propName.length() > 2
+ && propName.at(2).isUpper()) {
+ qmlWarning(this) << tr("Detected function \"%1\" in Connections element. "
+ "This is probably intended to be a signal handler but no "
+ "signal of the target matches the name.").arg(propName);
+ }
+ }
+}
+
+// TODO: Drop this as soon as we can
+void QQmlConnections::connectSignalsToBindings()
+{
+ Q_D(QQmlConnections);
QObject *target = this->target();
QQmlData *ddata = QQmlData::get(this);
QQmlContextData *ctxtdata = ddata ? ddata->outerContext : nullptr;
diff --git a/src/qml/types/qqmlconnections_p.h b/src/qml/types/qqmlconnections_p.h
index f6ad1eb46c..5d28e8e8be 100644
--- a/src/qml/types/qqmlconnections_p.h
+++ b/src/qml/types/qqmlconnections_p.h
@@ -69,7 +69,7 @@ class Q_AUTOTEST_EXPORT QQmlConnections : public QObject, public QQmlParserStatu
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QObject *target READ target WRITE setTarget NOTIFY targetChanged)
- Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged REVISION 1)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged REVISION 3)
Q_PROPERTY(bool ignoreUnknownSignals READ ignoreUnknownSignals WRITE setIgnoreUnknownSignals)
public:
@@ -87,14 +87,18 @@ public:
Q_SIGNALS:
void targetChanged();
- Q_REVISION(1) void enabledChanged();
+ Q_REVISION(3) void enabledChanged();
private:
void connectSignals();
+ void connectSignalsToMethods();
+ void connectSignalsToBindings();
+
void classBegin() override;
void componentComplete() override;
};
+// TODO: Drop this class as soon as we can
class QQmlConnectionsParser : public QQmlCustomParser
{
public:
diff --git a/src/qmlmodels/configure.json b/src/qmlmodels/configure.json
index 84eefed261..1ccca5e35e 100644
--- a/src/qmlmodels/configure.json
+++ b/src/qmlmodels/configure.json
@@ -30,7 +30,7 @@
"label": "QML table model",
"purpose": "Provides the TableModel QML type.",
"section": "QML",
- "condition": "features.qml-itemmodel",
+ "condition": "features.qml-itemmodel && features.qml-delegate-model",
"output": [ "privateFeature" ]
}
},
diff --git a/src/qmlmodels/qqmlmodelsmodule.cpp b/src/qmlmodels/qqmlmodelsmodule.cpp
index 884b7f78b2..4b753fe49a 100644
--- a/src/qmlmodels/qqmlmodelsmodule.cpp
+++ b/src/qmlmodels/qqmlmodelsmodule.cpp
@@ -81,7 +81,7 @@ void QQmlModelsModule::defineModule()
qmlRegisterType<QQmlObjectModel>(uri, 2, 1, "ObjectModel");
qmlRegisterType<QQmlObjectModel,3>(uri, 2, 3, "ObjectModel");
qmlRegisterType<QQmlInstantiator>(uri, 2, 1, "Instantiator");
- qmlRegisterType<QQmlInstanceModel>();
+ qmlRegisterAnonymousType<QQmlInstanceModel>(uri, 2);
#endif
#if QT_CONFIG(itemmodel)
qmlRegisterType<QItemSelectionModel>(uri, 2, 2, "ItemSelectionModel");
diff --git a/src/qmltest/quicktestevent.cpp b/src/qmltest/quicktestevent.cpp
index 5b07220c29..1e949615c2 100644
--- a/src/qmltest/quicktestevent.cpp
+++ b/src/qmltest/quicktestevent.cpp
@@ -241,7 +241,8 @@ namespace QtQuickTest
QTEST_ASSERT(stateKey == 0 || stateKey & Qt::KeyboardModifierMask);
stateKey &= static_cast<unsigned int>(Qt::KeyboardModifierMask);
- QWheelEvent we(pos, window->mapToGlobal(pos), QPoint(0, 0), QPoint(xDelta, yDelta), 0, Qt::Vertical, buttons, stateKey);
+ QWheelEvent we(pos, window->mapToGlobal(pos), QPoint(0, 0), QPoint(xDelta, yDelta), buttons,
+ stateKey, Qt::NoScrollPhase, false);
QSpontaneKeyEvent::setSpontaneous(&we); // hmmmm
if (!qApp->notify(window, &we))
diff --git a/src/quick/doc/images/declarative-qtlogo.png b/src/quick/doc/images/declarative-qtlogo.png
index 940d159ae4..b63f1384b1 100644
--- a/src/quick/doc/images/declarative-qtlogo.png
+++ b/src/quick/doc/images/declarative-qtlogo.png
Binary files differ
diff --git a/src/quick/doc/snippets/cmake-macros/examples.cmake b/src/quick/doc/snippets/cmake-macros/examples.cmake
new file mode 100644
index 0000000000..8ca6180f9b
--- /dev/null
+++ b/src/quick/doc/snippets/cmake-macros/examples.cmake
@@ -0,0 +1,6 @@
+#! [qt5_import_qml_plugins]
+find_package(Qt5 COMPONENTS Quick QmlImportScanner)
+add_executable(myapp main.cpp)
+target_link_libraries(myapp Qt5::Quick)
+qt5_import_qml_plugins(myapp)
+#! [qt5_import_plugins]
diff --git a/src/quick/doc/snippets/qml/transitions-list.qml b/src/quick/doc/snippets/qml/transitions-list.qml
index 06b9e39cc8..972d3ee14e 100644
--- a/src/quick/doc/snippets/qml/transitions-list.qml
+++ b/src/quick/doc/snippets/qml/transitions-list.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@@ -48,52 +48,105 @@
**
****************************************************************************/
-import QtQuick 2.0
+import QtQuick 2.13
Rectangle {
- width: 150; height: 250
+ id: page
+ width: 640
+ height: 500
- Rectangle {
- id: stopLight
- x: 25; y: 15; width: 100; height: 100
- }
- Rectangle {
- id: goLight
- x: 25; y: 135; width: 100; height: 100
- }
+ Image {
+ id: userIcon
+ x: topLeftRect.x
+ y: topLeftRect.y
- states: [
- State {
- name: "stop"
- PropertyChanges { target: stopLight; color: "red" }
- PropertyChanges { target: goLight; color: "black" }
- },
- State {
- name: "go"
- PropertyChanges { target: stopLight; color: "black" }
- PropertyChanges { target: goLight; color: "green" }
+ source: "../../images/declarative-qtlogo.png"
}
- ]
- state: "stop"
+ Rectangle {
+ id: topLeftRect
+ anchors { left: parent.left; top: parent.top; leftMargin: 10; topMargin: 20 }
+ width: 46; height: 54
+ color: "Transparent"; border.color: "Gray"; radius: 6
+ // Clicking here sets state to default state, returning image to initial position
+ TapHandler { onTapped: page.state = 'start' }
+ }
+
+ Rectangle {
+ id: middleRightRect
+ anchors { right: parent.right; verticalCenter: parent.verticalCenter; rightMargin: 20 }
+ width: 46; height: 54
+ color: "Transparent"; border.color: "Gray"; radius: 6
+ // Clicking in here sets the state to 'middleRight'
+ TapHandler { onTapped: page.state = 'middleRight' }
+ }
- MouseArea {
- anchors.fill: parent
- onClicked: parent.state == "stop" ?
- parent.state = "go" : parent.state = "stop"
- }
+ Rectangle {
+ id: bottomLeftRect
+ anchors { left: parent.left; bottom: parent.bottom; leftMargin: 10; bottomMargin: 20 }
+ width: 46; height: 54
+ color: "Transparent"; border.color: "Gray"; radius: 6
+ // Clicking in here sets the state to 'bottomLeft'
+ TapHandler { onTapped: page.state = 'bottomLeft' }
+ }
- //! [list of transitions]
- transitions: [
- Transition {
- from: "stop"; to: "go"
- PropertyAnimation { target: stopLight
- properties: "color"; duration: 1000 }
- },
- Transition {
- from: "go"; to: "stop"
- PropertyAnimation { target: goLight
- properties: "color"; duration: 1000 }
- } ]
- //! [list of transitions]
+ states: [
+ State {
+ name: "start"
+ PropertyChanges {
+ target: userIcon
+ explicit: true
+ x: topLeftRect.x
+ y: topLeftRect.y
+ }
+ },
+ State {
+ name: "middleRight"
+ PropertyChanges {
+ target: userIcon
+ explicit: true
+ x: middleRightRect.x
+ y: middleRightRect.y
+ }
+ },
+ State {
+ name: "bottomLeft"
+ PropertyChanges {
+ target: userIcon
+ explicit: true
+ x: bottomLeftRect.x
+ y: bottomLeftRect.y
+ }
+ }
+ ]
+//! [list of transitions]
+ transitions: [
+ Transition {
+ from: "*"; to: "middleRight"
+ NumberAnimation {
+ properties: "x,y";
+ easing.type: Easing.InOutQuad;
+ duration: 2000;
+ }
+ },
+ Transition {
+ from: "*"; to: "bottomLeft";
+ NumberAnimation {
+ properties: "x,y";
+ easing.type: Easing.InOutQuad;
+ duration: 200;
+ }
+ },
+ //If any other rectangle is clicked, the icon will return
+ //to the start position at a slow speed and bounce.
+ Transition {
+ from: "*"; to: "*";
+ NumberAnimation {
+ easing.type: Easing.OutBounce;
+ properties: "x,y";
+ duration: 4000;
+ }
+ }
+ ]
+//! [list of transitions]
}
diff --git a/src/quick/doc/src/cmake-macros.qdoc b/src/quick/doc/src/cmake-macros.qdoc
new file mode 100644
index 0000000000..b643a9e4e4
--- /dev/null
+++ b/src/quick/doc/src/cmake-macros.qdoc
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\page qtqml-cmake-qt5-import-qml-plugins.html
+\ingroup cmake-macros-qtqml
+
+\title qt5_import_qml_plugins
+
+\brief Scans \c{.qml} files and imports required QML static plugins
+
+\section1 Overview
+
+\badcode
+find_package(Qt5QmlImportScanner REQUIRED)
+qt5_import_qml_plugins(<TARGET>)
+\endcode
+
+\section1 Description
+
+Runs \c{qmlimportscanner} at configure time to find the static QML plugins
+used and links them to the given target.
+
+\note When used with a non-static Qt build, this function does nothing.
+
+This CMake command was introduced in Qt 5.14.
+
+\section1 Example
+
+\snippet cmake-macros/examples.cmake qt5_import_qml_plugins
+
+*/
diff --git a/src/quick/doc/src/concepts/positioning/righttoleft.qdoc b/src/quick/doc/src/concepts/positioning/righttoleft.qdoc
index 7c8cd735b3..1f3602cde1 100644
--- a/src/quick/doc/src/concepts/positioning/righttoleft.qdoc
+++ b/src/quick/doc/src/concepts/positioning/righttoleft.qdoc
@@ -148,7 +148,7 @@ To define the layout direction for a particular locale, declare the dedicated st
You can do this by first introducing this line
\code
-QT_TRANSLATE_NOOP("QGuiApplication", "QT_LAYOUT_DIRECTION");
+qsTr("QT_LAYOUT_DIRECTION","QGuiApplication");
\endcode
somewhere in your QML source code and calling \c lupdate to generate the translation source file.
diff --git a/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc b/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc
index 8edc5cb0b6..e83aa39734 100644
--- a/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc
+++ b/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc
@@ -31,15 +31,35 @@
\section1 Scene Graph Adaptations in Qt Quick
-Originally, Qt Quick always relied on OpenGL (OpenGL ES 2.0 or OpenGL 2.0) to parse the scene graph
-and render the results to a render target. From Qt 5.8 onwards, Qt Quick also supports rendering in
-software and with Direct3D 12.
+Originally, Qt Quick always relied on OpenGL (OpenGL ES 2.0 or OpenGL 2.0) to
+parse the scene graph and render the results to a render target
+
+From Qt 5.8 onwards, Qt Quick also supports rendering in software, with OpenVG,
+and with Direct3D 12. This is realized by having additional scene graph
+adaptations, either in form of plugins (d3d12, openvg) or built-in to the Qt
+Quick library (software). The default adaptation continues to rely directly on
+OpenGL.
+
+From Qt 5.14 onwards, the default adaptation gains the option of rendering via
+a graphics abstraction layer, the Qt Rendering Hardware Interface (RHI),
+provided by the \l QtGui module. When enabled, no direct OpenGL calls are made.
+Rather, the scene graph renders by using the APIs provided by the abstraction
+layer, which is then translated into OpenGL, Vulkan, Metal, or Direct 3D calls.
+Shader handling is also unified by writing shader code once, compiling to
+\l{https://www.khronos.org/spir/}{SPIR-V}, and then translating to the language
+appropriate for the various graphics APIs.
\target Switching Between the Adaptation Used by the Application
\section1 Switch Between Adaptations in Your Application
-The default rendering backend is still OpenGL, but in Qt builds with OpenGL support disabled, the
-default is the software renderer. You can override this in one of two ways:
+Unlike \c software or \c d3d12, the RHI-based renderer is not an additional
+adaptation, and is always built-in. As of Qt 5.14 it can be enabled by setting
+the environment variable \c{QSG_RHI} to a non-zero value before starting the
+application, or via \l QQuickWindow::setScenegraphBackend() in combination with
+\l QSGRendererInterface::GraphicsApi. When none of this is done, OpenGL is used
+directly like in previous versions.
+
+Switching to a different adaptation can be achieved in two ways:
\list
\li Use an environment variable - Set the \c{QT_QUICK_BACKEND} or the legacy
@@ -51,7 +71,8 @@ default is the software renderer. You can override this in one of two ways:
The following backends are supported:
\list
- \li OpenGL - Request with the \c{""} string or the QSGRendererInterface::OpenGL enum value.
+ \li Default - Request with the \c{""} string or a QSGRendererInterface::GraphicsApi enum value
+ different than the ones listed below.
\li Software - Request with the \c{"software"} string or the QSGRendererInterface::Software
enum value.
\li Direct3D 12 - Request with the \c{"d3d12"} string or the QSGRendererInterface::Direct3D12
@@ -64,16 +85,25 @@ To find out which backend is in use, you can enable basic scene graph informatio
\c{QSG_INFO} environment variable or the \c{qt.scenegraph.general} logging category. This results
in some information being printed onto the debug output, during application startup.
-\note Typically, adaptations other than OpenGL come with a set of limitations as they are unlikely
- to provide a feature set that's 100% compatible with OpenGL. However, these adaptations may
- provide their own specific advantages in certain areas. For more information on the various
- adaptations, refer to the sections below.
+\note In Qt builds with OpenGL disabled, the default adaptation is \c software.
+This may change in future releases.
+
+\note Typically, adaptations other than the default one come with a set of
+limitations as they are unlikely to provide a feature set that's 100%
+compatible with OpenGL. However, these adaptations may provide their own
+specific advantages in certain areas. For more information on the various
+adaptations, refer to the sections below.
+
+\section1 Default Adaptation
-\section1 OpenGL ES 2.0 and OpenGL 2.0 Adaptation
+When using OpenGL directly, the default adaptation is capable of providing the
+full Qt Quick 2 feature set. For more details, see
+\l{qtquick-visualcanvas-scenegraph-renderer.html}{Default Adaptation}.
-The OpenGL adaptation is the default adaptation, which is capable of providing the full Qt Quick 2
-feature set. For more details, see
-\l{qtquick-visualcanvas-scenegraph-renderer.html}{OpenGL Adaptation}.
+When using OpenGL, Vulkan, Metal, or Direct 3D via the RHI, the default
+adaptation is capable of providing most features, including the full batching
+renderer described in \l{qtquick-visualcanvas-scenegraph-renderer.html}{Default
+Adaptation}, but some additional features may not be available as of Qt 5.14.
\section1 Software Adaptation
diff --git a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
index ee6c501c71..b96d09996d 100644
--- a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
+++ b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
@@ -31,15 +31,13 @@
\section1 The Scene Graph in Qt Quick
-Qt Quick 2 makes use of a dedicated scene graph based and a series of
-adaptations of which the default uses OpenGL ES 2.0 or OpenGL 2.0 for
-its rendering. Using a scene graph for graphics rather than the
-traditional imperative painting systems (QPainter and
-similar), means the scene to be rendered can be retained between
-frames and the complete set of primitives to render is known before
-rendering starts. This opens up for a number of optimizations, such as
-batch rendering to minimize state changes and discarding obscured
-primitives.
+Qt Quick 2 makes use of a dedicated scene graph that is then traversed and
+rendered via a graphics API such as OpenGL ES, OpenGL, Vulkan, Metal, or Direct
+3D. Using a scene graph for graphics rather than the traditional imperative
+painting systems (QPainter and similar), means the scene to be rendered can be
+retained between frames and the complete set of primitives to render is known
+before rendering starts. This opens up for a number of optimizations, such as
+batch rendering to minimize state changes and discarding obscured primitives.
For example, say a user-interface contains a list of ten items
where each item has a background color, an icon and a text. Using the
@@ -63,9 +61,10 @@ independently of the state of the items. On many platforms, the scene
graph will even be rendered on a dedicated render thread while the GUI
thread is preparing the next frame's state.
-\note Much of the information listed on this page is specific to the
-default OpenGL adaptation of the Qt Quick Scene graph. For more information
-about the different scene graph adaptations see
+\note Much of the information listed on this page is specific to the built-in,
+default behavior of the Qt Quick Scene graph. When using an alternative scene
+graph adaptation, such as, the \c software adaptation, not all concepts may
+apply. For more information about the different scene graph adaptations see
\l{qtquick-visualcanvas-adaptations.html}{Scene Graph Adaptations}.
@@ -106,10 +105,10 @@ Custom nodes are added to the scene graph by subclassing
QQuickItem::updatePaintNode() and setting the
\l {QQuickItem::ItemHasContents} flag.
-\warning It is crucial that OpenGL operations and interaction with the
-scene graph happens exclusively on the render thread, primarily
-during the updatePaintNode() call. The rule of thumb is to only
-use classes with the "QSG" prefix inside the
+\warning It is crucial that native graphics (OpenGL, Vulkan, Metal, etc.)
+operations and interaction with the scene graph happens exclusively on the
+render thread, primarily during the updatePaintNode() call. The rule of thumb
+is to only use classes with the "QSG" prefix inside the
QQuickItem::updatePaintNode() function.
For more details, see the \l {Scene Graph - Custom Geometry}.
@@ -133,11 +132,11 @@ simplifies cleanup when the scene graph lives outside the GUI thread.
\section2 Materials
-The material describes how the interior of a geometry in a \l
-QSGGeometryNode is filled. It encapsulates an OpenGL shader program
-and provides ample flexibility in what can be achieved, though most of
-the Qt Quick items themselves only use very basic materials, such as
-solid color and texture fills.
+The material describes how the interior of a geometry in a \l QSGGeometryNode
+is filled. It encapsulates graphics shaders for the vertex and fragment stages
+of the graphics pipeline and provides ample flexibility in what can be
+achieved, though most of the Qt Quick items themselves only use very basic
+materials, such as solid color and texture fills.
For users who just want to apply custom shading to a QML Item type,
it is possible to do this directly in QML using the \l ShaderEffect
@@ -151,11 +150,11 @@ For more details, see the \l {Scene Graph - Simple Material}
\section2 Convenience Nodes
-The scene graph API is very low-level and focuses on performance
-rather than convenience. Writing custom geometries and materials from
-scratch, even the most basic ones, requires a non-trivial amount of
-code. For this reason, the API includes a few convenience classes to
-make the most common custom nodes readily available.
+The scene graph API is low-level and focuses on performance rather than
+convenience. Writing custom geometries and materials from scratch, even the
+most basic ones, requires a non-trivial amount of code. For this reason, the
+API includes a few convenience classes to make the most common custom nodes
+readily available.
\list
\li \l QSGSimpleRectNode - a QSGGeometryNode subclass which defines a
@@ -169,15 +168,16 @@ a rectangular geometry with a texture material.
\section1 Scene Graph and Rendering
-The rendering of the scene graph happens internally in the
-QQuickWindow class, and there is no public API to access it. There are,
-however, a few places in the rendering pipeline where the user can
-attach application code. This can be used to add custom scene graph
-content or render raw OpenGL content. The integration points are
-defined by the render loop.
+The rendering of the scene graph happens internally in the QQuickWindow class,
+and there is no public API to access it. There are, however, a few places in
+the rendering pipeline where the user can attach application code. This can be
+used to add custom scene graph content or to insert arbitrary rendering
+commands by directly calling the graphics API (OpenGL, Vulkan, Metal, etc.)
+that is in use by the scene graph. The integration points are defined by the
+render loop.
-For detailed description of how the scene graph renderer for OpenGL
-works, see \l {Qt Quick Scene Graph OpenGL Renderer}.
+For detailed description of how the scene graph renderer works, see \l {Qt
+Quick Scene Graph Default Renderer}.
There are three render loop variants available: \c basic, \c windows,
and \c threaded. Out of these, \c basic and \c windows are
@@ -189,14 +189,14 @@ satisfactory, or for testing purposes, the environment variable
verify which render loop is in use, enable the \c qt.scenegraph.general
\l {QLoggingCategory}{logging category}.
-\note The \c threaded and \c windows render loops rely on the OpenGL
-implementation for throttling by requesting a swap interval of 1. Some
-graphics drivers allow users to override this setting and turn it off,
-ignoring Qt's request. Without blocking in the swap buffers operation
-(or elsewhere), the render loop will run animations too fast and spin
-the CPU at 100%. If a system is known to be unable to provide
-vsync-based throttling, use the \c basic render loop instead by
-setting \c {QSG_RENDER_LOOP=basic} in the environment.
+\note The \c threaded and \c windows render loops rely on the graphics API
+implementation for throttling, for example, by requesting a swap interval of 1
+in case of OpenGL. Some graphics drivers allow users to override this setting
+and turn it off, ignoring Qt's request. Without blocking in the swap buffers
+operation (or elsewhere), the render loop will run animations too fast and spin
+the CPU at 100%. If a system is known to be unable to provide vsync-based
+throttling, use the \c basic render loop instead by setting \c
+{QSG_RENDER_LOOP=basic} in the environment.
\section2 Threaded Render Loop ("threaded")
@@ -207,8 +207,9 @@ waiting for a blocking swap buffer call. This offers significant
performance improvements, but imposes certain restrictions on where
and when interaction with the scene graph can happen.
-The following is a simple outline of how a frame gets
-composed with the threaded render loop.
+The following is a simple outline of how a frame gets rendered with the
+threaded render loop and OpenGL. The steps are the same with other graphics
+APIs as well, apart from the OpenGL context specifics.
\image sg-renderloop-threaded.png
@@ -219,8 +220,8 @@ to be called. This can be the result of for instance an animation or
user input. An event is posted to the render thread to initiate a new
frame.
-\li The render thread prepares to draw a new frame and makes the
-OpenGL context current and initiates a block on the GUI thread.
+\li The render thread prepares to draw a new frame and initiates a block on the
+GUI thread.
\li While the render thread is preparing the new frame, the GUI thread
calls QQuickItem::updatePolish() to do final touch-up of items before
@@ -243,23 +244,27 @@ time the QML items and the nodes in the scene graph interact.
\li The scene graph is rendered:
\list 1
- \li The QQuickWindow::beforeRendering() signal is
- emitted. Applications can make direct connections
- (using Qt::DirectConnection) to this signal to use custom OpenGL calls
- which will then stack visually beneath the QML scene.
+ \li The QQuickWindow::beforeRendering() signal is emitted. Applications can
+ make direct connections (using Qt::DirectConnection) to this signal to use
+ custom graphics API calls which will then stack visually beneath the QML
+ scene.
\li Items that have specified QSGNode::UsePreprocess, will have their
QSGNode::preprocess() function invoked.
- \li The renderer processes the nodes and calls OpenGL functions.
+ \li The renderer processes the nodes.
- \li The QQuickWindow::afterRendering() signal is
- emitted. Applications can make direct connections
- (using Qt::DirectConnection) to this signal to use custom OpenGL calls
- which will then stack visually over the QML scene.
+ \li The renderer generates states and records draw calls for the graphics
+ API in use.
- \li The rendered frame is swapped and QQuickWindow::frameSwapped()
- is emitted.
+ \li The QQuickWindow::afterRendering() signal is emitted. Applications can
+ make direct connections (using Qt::DirectConnection) to this signal to
+ issue custom graphics API calls which will then stack visually over the QML
+ scene.
+
+ \li The frame is now ready. The buffers are swapped (OpenGL), or a present
+ command is recorded and the command buffers are submitted to a graphics
+ queue (Vulkan, Metal). QQuickWindow::frameSwapped() is emitted.
\endlist
@@ -269,37 +274,38 @@ animations, process events, etc.
\endlist
The threaded renderer is currently used by default on Windows with
-opengl32.dll, Linux with non-Mesa based drivers, mobile
-platforms, and Embedded Linux with EGLFS but this is subject to
-change. It is possible to force use of the threaded renderer by
-setting \c {QSG_RENDER_LOOP=threaded} in the environment.
+opengl32.dll, Linux excluding Mesa llvmpipe, \macos with Metal, mobile
+platforms, and Embedded Linux with EGLFS, and with Vulkan regardless of the
+platform, but this is subject to change. It is always possible to force use of
+the threaded renderer by setting \c {QSG_RENDER_LOOP=threaded} in the
+environment.
\section2 Non-threaded Render Loops ("basic" and "windows")
-The non-threaded render loop is currently used by default on Windows
-with ANGLE or a non-default opengl32 implementation, \macos, and Linux with
-Mesa drivers. For the latter this is mostly a precautionary measure,
-as not all combinations of OpenGL drivers and windowing systems have
-been tested. At the same time implementations like ANGLE or Mesa
-llvmpipe are not able to function properly with threaded rendering at
-all so not using threaded rendering is essential for these.
+The non-threaded render loop is currently used by default on Windows with ANGLE
+or a non-default opengl32 implementation, \macos with OpenGL, and Linux with
+some drivers. For the latter this is mostly a precautionary measure, as not all
+combinations of OpenGL drivers and windowing systems have been tested. At the
+same time implementations like ANGLE or Mesa llvmpipe are not able to function
+properly with threaded rendering at all so not using threaded rendering is
+essential for these.
-On macOS, the threaded render loop is not supported when building
-with XCode 10 (10.14 SDK) or later, since this opts in to layer-backed
-views on macOS 10.14. You can build with Xcode 9 (10.13 SDK) to opt
-out of layer-backing, in which case the threaded render loop is
-available and used by default.
+On macOS and OpenGL, the threaded render loop is not supported when building
+with XCode 10 (10.14 SDK) or later, since this opts in to layer-backed views on
+macOS 10.14. You can build with Xcode 9 (10.13 SDK) to opt out of
+layer-backing, in which case the threaded render loop is available and used by
+default. There is no such restriction with Metal.
-By default \c windows is used for non-threaded rendering on Windows
-with ANGLE, while \c basic is used for all other platforms when
-non-threaded rendering is needed.
+By default \c windows is used for non-threaded rendering on Windows with ANGLE,
+while \c basic is used for all other platforms when non-threaded rendering is
+needed.
-Even when using the non-threaded render loop, you should write your
-code as if you are using the threaded renderer, as failing to do so
-will make the code non-portable.
+Even when using the non-threaded render loop, you should write your code as if
+you are using the threaded renderer, as failing to do so will make the code
+non-portable.
-The following is a simplified illustration of the frame rendering
-sequence in the non-threaded renderer.
+The following is a simplified illustration of the frame rendering sequence in
+the non-threaded renderer.
\image sg-renderloop-singlethreaded.png
@@ -314,32 +320,37 @@ time. It is possible to implement either a threaded or non-threaded
behavior similar to the ones shown above.
-\section2 Mixing Scene Graph and OpenGL
+\section2 Mixing Scene Graph and the native graphics API
-The scene graph offers two methods for integrating OpenGL content:
-by calling OpenGL commands directly and by creating a textured node
-in the scene graph.
+The scene graph offers two methods for integrating application-provided
+graphics commands: by issuing OpenGL, Vulkan, Metal, etc. commands directly,
+and by creating a textured node in the scene graph.
By connecting to the \l QQuickWindow::beforeRendering() and \l
-QQuickWindow::afterRendering() signals, applications can make OpenGL
-calls directly into the same context as the scene graph is rendering
-to. As the signal names indicate, the user can then render OpenGL
-content either under a Qt Quick scene or over it. The benefit of
-integrating in this manner is that no extra framebuffer nor memory is
-needed to perform the rendering. The downside is that Qt Quick decides
-when to call the signals and this is the only time the OpenGL
-application is allowed to draw.
+QQuickWindow::afterRendering() signals, applications can make OpenGL calls
+directly into the same context as the scene graph is rendering to. With APIs
+like Vulkan or Metal, applications can query native objects, such as, the scene
+graph's command buffer, via QSGRendererInterface, and record commands to it as
+they see fit. As the signal names indicate, the user can then render content
+either under a Qt Quick scene or over it. The benefit of integrating in this
+manner is that no extra framebuffer nor memory is needed to perform the
+rendering, and a possibly expensive texturing step is eliminated. The downside
+is that Qt Quick decides when to call the signals and this is the only time the
+OpenGL application is allowed to draw.
The \l {Scene Graph - OpenGL Under QML} example gives an example on
-how to use these signals.
+how to use these signals using OpenGL.
+
+The \l {Scene Graph - Metal Under QML} example gives an example on
+how to use these signals using Metal.
-The other alternative is to create a QQuickFramebufferObject, render
-into it, and let it be displayed in the scene graph as a texture.
-The \l {Scene Graph - Rendering FBOs} example shows how this can be
-done. It is also possible to combine multiple rendering contexts and
-multiple threads to create content to be displayed in the scene graph.
-The \l {Scene Graph - Rendering FBOs in a thread} examples show how
-this can be done.
+The other alternative, only available for OpenGL currently, is to create a
+QQuickFramebufferObject, render into it, and let it be displayed in the scene
+graph as a texture. The \l {Scene Graph - Rendering FBOs} example shows how
+this can be done. It is also possible to combine multiple rendering contexts
+and multiple threads to create content to be displayed in the scene graph. The
+\l {Scene Graph - Rendering FBOs in a thread} examples show how this can be
+done.
\warning When mixing OpenGL content with scene graph rendering, it is
important the application does not leave the OpenGL context in a state
@@ -347,8 +358,8 @@ with buffers bound, attributes enabled, special values in the z-buffer
or stencil-buffer or similar. Doing so can result in unpredictable
behavior.
-\warning The OpenGL rendering code must be thread aware, as the
-rendering might be happening outside the GUI thread.
+\warning The custom rendering code must be thread aware in the sense that it
+should not assume being executed on the GUI (main) thread of the application.
\section2 Custom Items using QPainter
@@ -386,6 +397,15 @@ addition to being helpful to Qt contributors.
\endlist
+The legacy \c{QSG_INFO} environment variable is also available. Setting it to a
+non-zero value enables the \c{qt.scenegraph.general} category.
+
+\note When encountering graphics problems, or when in doubt which render loop
+or graphics API is in use, always start the application with at least
+\c{qt.scenegraph.general} and \c{qt.rhi.*} enabled, or \c{QSG_INFO=1} set. This
+will then print some essential information onto the debug output during
+initialization.
+
\section1 Scene Graph Backend
In addition to the public API, the scene graph has an adaptation layer
@@ -419,13 +439,12 @@ with multiple windows.
*/
/*!
- \title Qt Quick Scene Graph OpenGL Renderer
+ \title Qt Quick Scene Graph Default Renderer
\page qtquick-visualcanvas-scenegraph-renderer.html
- This document explains how the scene graph renderer for OpenGL
- works internally
+ This document explains how the default scene graph renderer works internally,
so that one can write code that uses it in an optimal fashion, both
- performance-wise and feature-wise.
+ performance and feature-wise.
One does not need to understand the internals of the renderer to get
good performance. However, it might help when integrating with the
@@ -442,8 +461,8 @@ with multiple windows.
platforms be processed and rendered in a separate thread. The
renderer is a self contained part of the scene graph which traverses
the QSGNode tree and uses geometry defined in QSGGeometryNode and
- shader state defined in QSGMaterial to schedule OpenGL state change
- and draw calls.
+ shader state defined in QSGMaterial to update the graphics state and
+ generate draw calls.
If needed, the renderer can be completely replaced using the
internal scene graph back-end API. This is mostly interesting for
@@ -457,11 +476,15 @@ with multiple windows.
\section1 Batching
- Where a traditional 2D API, such as QPainter, Cairo or Context2D, is
- written to handle thousands of individual draw calls per frame,
- OpenGL is a pure hardware API and performs best when the number of
- draw calls is very low and state changes are kept to a
- minimum. Consider the following use case:
+ Whereas a traditional 2D API, such as QPainter, Cairo or Context2D, is
+ written to handle thousands of individual draw calls per frame, OpenGL and
+ other hardware accelerated APIs perform best when the number of draw calls is
+ very low and state changes are kept to a minimum.
+
+ \note While \c OpenGL is used as an example in the following sections, the
+ same concepts apply to other graphics APIs as well.
+
+ Consider the following use case:
\image visualcanvas_list.png
@@ -934,4 +957,65 @@ with multiple windows.
\image visualize-overdraw-1.png "overdraw-1"
\image visualize-overdraw-2.png "overdraw-2"
\c QSG_VISUALIZE=overdraw
+
+ \section1 Rendering via the Qt Rendering Hardware Interface
+
+ From Qt 5.14 onwards, the default adaptation gains the option of rendering
+ via a graphics abstraction layer, the Qt Rendering Hardware Interface (RHI),
+ provided by the \l QtGui module. When enabled, no direct OpenGL calls are
+ made. Rather, the scene graph renders by using the APIs provided by the
+ abstraction layer, which is then translated into OpenGL, Vulkan, Metal, or
+ Direct 3D calls. Shader handling is also unified by writing shader code once,
+ compiling to \l{https://www.khronos.org/spir/}{SPIR-V}, and then translating
+ to the language appropriate for the various graphics APIs.
+
+ To enable this instead of directly using OpenGL, the following environment
+ variables can be used:
+
+ \table 100%
+ \header
+ \li Environment Variable
+ \li Possible Values
+ \li Description
+
+ \row
+ \li \c QSG_RHI
+ \li \c 1
+ \li Enables rendering via the RHI. The targeted graphics API is chosen based on
+ the platform, unless overridden by \c QSG_RHI_BACKEND. The defaults are currently
+ Direct3D 11 for Windows, Metal for macOS, OpenGL elsehwere.
+
+ \row
+ \li \c QSG_RHI_BACKEND
+ \li \c vulkan, \c metal, \c opengl, \c d3d11
+ \li Requests the specific RHI backend.
+
+ \row
+ \li \c QSG_INFO
+ \li \c 1
+ \li Like with the OpenGL-based rendering path, setting this enables printing system
+ information when initializing the Qt Quick scene graph. This can be very useful for
+ troubleshooting.
+
+ \row
+ \li \c QSG_RHI_DEBUG_LAYER
+ \li \c 1
+ \li Where applicable (Vulkan, Direct3D), enables the graphics API implementation's debug
+ and/or validation layers, if available.
+
+ \endtable
+
+ Applications wishing to always run with a single given graphics API, can
+ request this via C++ as well. For example, the following call made early in
+ main(), before constructing any QQuickWindow, forces the use of Vulkan (and
+ will fail otherwise);
+
+ \badcode
+ QQuickWindow::setSceneGraphBackend(QSGRendererInterface::VulkanRhi);
+ \endcode
+
+ See QSGRendererInterface::GraphicsApi. The enum values ending in \c Rhi are
+ equivalent in effect to running with both \c QSG_RHI and \c QSG_RHI_BACKEND
+ set.
+
*/
diff --git a/src/quick/doc/src/concepts/visualcanvas/topic.qdoc b/src/quick/doc/src/concepts/visualcanvas/topic.qdoc
index cb6b3564f2..677e5bd739 100644
--- a/src/quick/doc/src/concepts/visualcanvas/topic.qdoc
+++ b/src/quick/doc/src/concepts/visualcanvas/topic.qdoc
@@ -56,12 +56,15 @@ See the documentation about the \l{qtquick-visualcanvas-visualparent.html}
\section1 Scene Graph
Modern computer systems and devices use graphics processing units or GPUs to
-render graphics. Qt Quick can leverage this graphics hardware by using graphics
-APIs like OpenGL. The default graphics adaptation for Qt Quick requires OpenGL and
-it is used to display applications developed with Qt Quick in QML. In particular,
-Qt Quick defines a scene graph which is then rendered. See the documentation about the
-\l{qtquick-visualcanvas-scenegraph.html}{Scene Graph} for in-depth information about
-the concept of a scene graph and why it is beneficial, and about the scene graph
-adaptations provided by Qt Quick.
+render graphics. Qt Quick can leverage this graphics hardware by using graphics
+APIs like \l{https://www.khronos.org/opengl/}{OpenGL},
+\l{https://www.khronos.org/vulkan/}{Vulkan}, or
+\l{https://developer.apple.com/documentation/metal}{Metal}. The default
+graphics adaptation for Qt Quick requires OpenGL and it is used to display
+applications developed with Qt Quick in QML. In particular, Qt Quick defines a
+scene graph which is then rendered. See the documentation about the
+\l{qtquick-visualcanvas-scenegraph.html}{Scene Graph} for in-depth information
+about the concept of a scene graph and why it is beneficial, and about the
+scene graph adaptations provided by Qt Quick.
*/
diff --git a/src/quick/doc/src/examples.qdoc b/src/quick/doc/src/examples.qdoc
index 77475e9812..9034c90eb8 100644
--- a/src/quick/doc/src/examples.qdoc
+++ b/src/quick/doc/src/examples.qdoc
@@ -172,12 +172,15 @@ Creator.
\b{Scene Graph}
\list
\li \l{Scene Graph - OpenGL Under QML}{OpenGL Under QML}
+ \li \l{Scene Graph - Metal Under QML}{Metal Under QML}
+ \li \l{Scene Graph - Direct3D 11 Under QML}{Direct3D 11 Under QML}
\li \l{Scene Graph - Painted Item}{Painted Item}
\li \l{Scene Graph - Custom Geometry}{Custom Geometry}
\li \l{Scene Graph - Graph}{Graph}
\li \l{Scene Graph - Simple Material}{Simple Material}
\li \l{Scene Graph - Rendering FBOs}{Rendering FBOs}
\li \l{Scene Graph - Rendering FBOs in a thread}{Rendering FBOs in a thread}
+ \li \l{Scene Graph - Custom Rendering with QSGRenderNode}{Render Node}
\endlist
\enddiv
\enddiv
diff --git a/src/quick/handlers/qquickdraghandler_p.h b/src/quick/handlers/qquickdraghandler_p.h
index 18c1fd841d..e8f47163ed 100644
--- a/src/quick/handlers/qquickdraghandler_p.h
+++ b/src/quick/handlers/qquickdraghandler_p.h
@@ -62,7 +62,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickDragHandler : public QQuickMultiPointHandler
Q_PROPERTY(QQuickDragAxis * xAxis READ xAxis CONSTANT)
Q_PROPERTY(QQuickDragAxis * yAxis READ yAxis CONSTANT)
Q_PROPERTY(QVector2D translation READ translation NOTIFY translationChanged)
- Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged)
+ Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged REVISION 14)
public:
enum SnapMode {
@@ -89,7 +89,7 @@ public:
Q_SIGNALS:
void translationChanged();
- void snapModeChanged();
+ Q_REVISION(14) void snapModeChanged();
protected:
void onActiveChanged() override;
diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp
index 255e47d73a..a10064a665 100644
--- a/src/quick/handlers/qquicktaphandler.cpp
+++ b/src/quick/handlers/qquicktaphandler.cpp
@@ -78,8 +78,8 @@ int QQuickTapHandler::m_touchMultiTapDistanceSquared(-1);
\l gesturePolicy to \c TapHandler.ReleaseWithinBounds.
For multi-tap gestures (double-tap, triple-tap etc.), the distance moved
- must not exceed QPlatformTheme::MouseDoubleClickDistance with mouse and
- QPlatformTheme::TouchDoubleTapDistance with touch, and the time between
+ must not exceed QStyleHints::mouseDoubleClickDistance() with mouse and
+ QStyleHints::touchDoubleTapDistance() with touch, and the time between
taps must not exceed QStyleHints::mouseDoubleClickInterval().
\sa MouseArea
@@ -90,11 +90,9 @@ QQuickTapHandler::QQuickTapHandler(QQuickItem *parent)
{
if (m_mouseMultiClickDistanceSquared < 0) {
m_multiTapInterval = qApp->styleHints()->mouseDoubleClickInterval() / 1000.0;
- m_mouseMultiClickDistanceSquared = QGuiApplicationPrivate::platformTheme()->
- themeHint(QPlatformTheme::MouseDoubleClickDistance).toInt();
+ m_mouseMultiClickDistanceSquared = qApp->styleHints()->mouseDoubleClickDistance();
m_mouseMultiClickDistanceSquared *= m_mouseMultiClickDistanceSquared;
- m_touchMultiTapDistanceSquared = QGuiApplicationPrivate::platformTheme()->
- themeHint(QPlatformTheme::TouchDoubleTapDistance).toInt();
+ m_touchMultiTapDistanceSquared = qApp->styleHints()->touchDoubleTapDistance();
m_touchMultiTapDistanceSquared *= m_touchMultiTapDistanceSquared;
}
}
@@ -410,9 +408,9 @@ void QQuickTapHandler::updateTimeHeld()
\since 5.11
This signal is emitted when the \c parent Item is tapped twice within a
- short span of time (QStyleHints::mouseDoubleClickInterval) and distance
- (QPlatformTheme::MouseDoubleClickDistance or
- QPlatformTheme::TouchDoubleTapDistance). This signal always occurs after
+ short span of time (QStyleHints::mouseDoubleClickInterval()) and distance
+ (QStyleHints::mouseDoubleClickDistance() or
+ QStyleHints::touchDoubleTapDistance()). This signal always occurs after
\l singleTapped, \l tapped, and \l tapCountChanged. The \c eventPoint
signal parameter contains information from the release event about the
point that was tapped.
diff --git a/src/quick/items/qquickanimatedimage.cpp b/src/quick/items/qquickanimatedimage.cpp
index fe445425e7..bebefc1b22 100644
--- a/src/quick/items/qquickanimatedimage.cpp
+++ b/src/quick/items/qquickanimatedimage.cpp
@@ -67,7 +67,7 @@ QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine
.arg(current));
}
if (!requestedUrl.isEmpty()) {
- if (QQuickPixmap::isCached(requestedUrl, QSize(), QQuickImageProviderOptions()))
+ if (QQuickPixmap::isCached(requestedUrl, QSize(), 0, QQuickImageProviderOptions()))
pixmap = new QQuickPixmap(engine, requestedUrl);
else
pixmap = new QQuickPixmap(requestedUrl, movie->currentImage());
@@ -139,6 +139,8 @@ QQuickAnimatedImage::QQuickAnimatedImage(QQuickItem *parent)
: QQuickImage(*(new QQuickAnimatedImagePrivate), parent)
{
connect(this, &QQuickImageBase::cacheChanged, this, &QQuickAnimatedImage::onCacheChanged);
+ connect(this, &QQuickImageBase::currentFrameChanged, this, &QQuickAnimatedImage::frameChanged);
+ connect(this, &QQuickImageBase::frameCountChanged, this, &QQuickAnimatedImage::frameCountChanged);
}
QQuickAnimatedImage::~QQuickAnimatedImage()
@@ -464,7 +466,7 @@ void QQuickAnimatedImage::movieUpdate()
if (d->movie) {
d->setPixmap(*d->infoForCurrentFrame(qmlEngine(this)));
- emit frameChanged();
+ emit currentFrameChanged();
}
}
diff --git a/src/quick/items/qquickanimatedimage_p.h b/src/quick/items/qquickanimatedimage_p.h
index 6b5db215bd..ef5af6b387 100644
--- a/src/quick/items/qquickanimatedimage_p.h
+++ b/src/quick/items/qquickanimatedimage_p.h
@@ -85,10 +85,10 @@ public:
bool isPaused() const;
void setPaused(bool pause);
- int currentFrame() const;
- void setCurrentFrame(int frame);
+ int currentFrame() const override;
+ void setCurrentFrame(int frame) override;
- int frameCount() const;
+ int frameCount() const override;
qreal speed() const;
void setSpeed(qreal speed);
diff --git a/src/quick/items/qquickborderimage.cpp b/src/quick/items/qquickborderimage.cpp
index c53a39ca09..430fa1b094 100644
--- a/src/quick/items/qquickborderimage.cpp
+++ b/src/quick/items/qquickborderimage.cpp
@@ -343,7 +343,7 @@ void QQuickBorderImage::load()
QUrl loadUrl = d->url;
resolve2xLocalFile(d->url, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio);
- d->pix.load(qmlEngine(this), loadUrl, d->sourcesize * d->devicePixelRatio, options);
+ d->pix.load(qmlEngine(this), loadUrl, d->sourcesize * d->devicePixelRatio, options, QQuickImageProviderOptions(), d->currentFrame, d->frameCount);
if (d->pix.isLoading()) {
if (d->progress != 0.0) {
@@ -534,6 +534,10 @@ void QQuickBorderImage::requestFinished()
d->oldSourceSize = sourceSize();
emit sourceSizeChanged();
}
+ if (d->frameCount != d->pix.frameCount()) {
+ d->frameCount = d->pix.frameCount();
+ emit frameCountChanged();
+ }
pixmapChange();
}
@@ -693,6 +697,18 @@ void QQuickBorderImage::pixmapChange()
update();
}
+/*!
+ \qmlproperty int QtQuick::BorderImage::currentFrame
+ \qmlproperty int QtQuick::BorderImage::frameCount
+ \since 5.14
+
+ currentFrame is the frame that is currently visible. The default is \c 0.
+ You can set it to a number between \c 0 and \c {frameCount - 1} to display a
+ different frame, if the image contains multiple frames.
+
+ frameCount is the number of frames in the image. Most images have only one frame.
+*/
+
QT_END_NAMESPACE
#include "moc_qquickborderimage_p.cpp"
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index ad3a39dd71..b0cfbaad6d 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -1448,7 +1448,7 @@ QQuickPointerEvent *QQuickPointerScrollEvent::reset(QEvent *event)
m_synthSource = ev->source();
m_inverted = ev->inverted();
- m_point->reset(Qt::TouchPointMoved, ev->posF(), quint64(1) << 24, ev->timestamp()); // mouse has device ID 1
+ m_point->reset(Qt::TouchPointMoved, ev->position(), quint64(1) << 24, ev->timestamp()); // mouse has device ID 1
}
#endif
// TODO else if (event->type() == QEvent::Scroll) ...
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index 7e1f54f07e..cf3cd9f48e 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -1489,7 +1489,7 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
d->vData.velocity = 0;
d->hData.velocity = 0;
d->timer.start();
- d->maybeBeginDrag(currentTimestamp, event->posF());
+ d->maybeBeginDrag(currentTimestamp, event->position());
break;
case Qt::NoScrollPhase: // default phase with an ordinary wheel mouse
case Qt::ScrollUpdate:
@@ -1571,7 +1571,8 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
QVector2D velocity(xDelta / elapsed, yDelta / elapsed);
d->lastPosTime = currentTimestamp;
d->accumulatedWheelPixelDelta += QVector2D(event->pixelDelta());
- d->drag(currentTimestamp, event->type(), event->posF(), d->accumulatedWheelPixelDelta, true, !d->scrollingPhase, true, velocity);
+ d->drag(currentTimestamp, event->type(), event->position(), d->accumulatedWheelPixelDelta,
+ true, !d->scrollingPhase, true, velocity);
event->accept();
}
diff --git a/src/quick/items/qquickframebufferobject.cpp b/src/quick/items/qquickframebufferobject.cpp
index 48f8b8db5c..190bc6853c 100644
--- a/src/quick/items/qquickframebufferobject.cpp
+++ b/src/quick/items/qquickframebufferobject.cpp
@@ -109,6 +109,10 @@ public:
* and can be used directly in \l {ShaderEffect}{ShaderEffects} and other
* classes that consume texture providers.
*
+ * \warning This class is only suitable when working directly with OpenGL. It
+ * is not compatible with the \l{Scene Graph Adaptations}{RHI-based rendering
+ * path}.
+ *
* \sa {Scene Graph - Rendering FBOs}, {Scene Graph and Rendering}
*/
diff --git a/src/quick/items/qquickframebufferobject.h b/src/quick/items/qquickframebufferobject.h
index d66ca40b3a..db143e48cf 100644
--- a/src/quick/items/qquickframebufferobject.h
+++ b/src/quick/items/qquickframebufferobject.h
@@ -44,11 +44,12 @@
QT_BEGIN_NAMESPACE
-
class QOpenGLFramebufferObject;
class QQuickFramebufferObjectPrivate;
class QSGFramebufferObjectNode;
+// ### Qt 6: To be removed. To be seen if an alternative will need to be introduced.
+
class Q_QUICK_EXPORT QQuickFramebufferObject : public QQuickItem
{
Q_OBJECT
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index dfbe271606..c7e7ccea55 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -687,7 +687,6 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
yOffset = qCeil(height() - pixHeight);
switch (d->fillMode) {
- default:
case Stretch:
targetRect = QRectF(0, 0, width(), height());
sourceRect = d->pix.rect();
@@ -699,7 +698,7 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
break;
case PreserveAspectCrop: {
- targetRect = QRect(0, 0, width(), height());
+ targetRect = QRectF(0, 0, width(), height());
qreal wscale = width() / qreal(d->pix.width());
qreal hscale = height() / qreal(d->pix.height());
@@ -751,7 +750,7 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
targetRect = QRectF(x + xOffset, y + yOffset, w, h);
sourceRect = QRectF(x, y, w, h);
break;
- };
+ }
qreal nsWidth = (hWrap == QSGTexture::Repeat || d->fillMode == Pad) ? d->pix.width() / d->devicePixelRatio : d->pix.width();
qreal nsHeight = (vWrap == QSGTexture::Repeat || d->fillMode == Pad) ? d->pix.height() / d->devicePixelRatio : d->pix.height();
@@ -889,4 +888,16 @@ void QQuickImage::setMipmap(bool use)
By default, this property is set to false.
*/
+/*!
+ \qmlproperty int QtQuick::Image::currentFrame
+ \qmlproperty int QtQuick::Image::frameCount
+ \since 5.14
+
+ currentFrame is the frame that is currently visible. The default is \c 0.
+ You can set it to a number between \c 0 and \c {frameCount - 1} to display a
+ different frame, if the image contains multiple frames.
+
+ frameCount is the number of frames in the image. Most images have only one frame.
+*/
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickimage_p.h b/src/quick/items/qquickimage_p.h
index 7fb4413900..257cde5313 100644
--- a/src/quick/items/qquickimage_p.h
+++ b/src/quick/items/qquickimage_p.h
@@ -66,8 +66,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickImage : public QQuickImageBase
Q_PROPERTY(qreal paintedHeight READ paintedHeight NOTIFY paintedGeometryChanged)
Q_PROPERTY(HAlignment horizontalAlignment READ horizontalAlignment WRITE setHorizontalAlignment NOTIFY horizontalAlignmentChanged)
Q_PROPERTY(VAlignment verticalAlignment READ verticalAlignment WRITE setVerticalAlignment NOTIFY verticalAlignmentChanged)
- Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged REVISION 1)
- Q_PROPERTY(bool autoTransform READ autoTransform WRITE setAutoTransform NOTIFY autoTransformChanged REVISION 2)
+ Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged REVISION 3)
+ Q_PROPERTY(bool autoTransform READ autoTransform WRITE setAutoTransform NOTIFY autoTransformChanged REVISION 5)
public:
QQuickImage(QQuickItem *parent=nullptr);
@@ -112,8 +112,8 @@ Q_SIGNALS:
void paintedGeometryChanged();
void horizontalAlignmentChanged(HAlignment alignment);
void verticalAlignmentChanged(VAlignment alignment);
- Q_REVISION(1) void mipmapChanged(bool);
- Q_REVISION(2) void autoTransformChanged();
+ Q_REVISION(3) void mipmapChanged(bool);
+ Q_REVISION(5) void autoTransformChanged();
private Q_SLOTS:
void invalidateSceneGraph();
diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp
index 729d326625..8bab14bfd1 100644
--- a/src/quick/items/qquickimagebase.cpp
+++ b/src/quick/items/qquickimagebase.cpp
@@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE
// if they're not happy with our implementation of it.
bool QQuickImageBasePrivate::updateDevicePixelRatio(qreal targetDevicePixelRatio)
{
- // QQuickImageProvider and SVG can generate a high resolution image when
+ // QQuickImageProvider and SVG and PDF can generate a high resolution image when
// sourceSize is set (this function is only called if it's set).
// If sourceSize is not set then the provider default size will be used, as usual.
bool setDevicePixelRatio = false;
@@ -64,7 +64,8 @@ bool QQuickImageBasePrivate::updateDevicePixelRatio(qreal targetDevicePixelRatio
} else {
QString stringUrl = url.path(QUrl::PrettyDecoded);
if (stringUrl.endsWith(QLatin1String("svg")) ||
- stringUrl.endsWith(QLatin1String("svgz"))) {
+ stringUrl.endsWith(QLatin1String("svgz")) ||
+ stringUrl.endsWith(QLatin1String("pdf"))) {
setDevicePixelRatio = true;
}
}
@@ -210,6 +211,36 @@ bool QQuickImageBase::mirror() const
return d->mirror;
}
+void QQuickImageBase::setCurrentFrame(int frame)
+{
+ Q_D(QQuickImageBase);
+ if (frame == d->currentFrame || frame < 0 || (isComponentComplete() && frame >= d->pix.frameCount()))
+ return;
+
+ d->currentFrame = frame;
+
+ if (isComponentComplete()) {
+ if (frame > 0)
+ d->cache = false;
+ load();
+ update();
+ }
+
+ emit currentFrameChanged();
+}
+
+int QQuickImageBase::currentFrame() const
+{
+ Q_D(const QQuickImageBase);
+ return d->currentFrame;
+}
+
+int QQuickImageBase::frameCount() const
+{
+ Q_D(const QQuickImageBase);
+ return d->frameCount;
+}
+
void QQuickImageBase::load()
{
Q_D(QQuickImageBase);
@@ -260,7 +291,7 @@ void QQuickImageBase::load()
resolve2xLocalFile(d->url, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio);
}
- d->pix.load(qmlEngine(this), loadUrl, d->sourcesize * d->devicePixelRatio, options, d->providerOptions);
+ d->pix.load(qmlEngine(this), loadUrl, d->sourcesize * d->devicePixelRatio, options, d->providerOptions, d->currentFrame, d->frameCount);
if (d->pix.isLoading()) {
if (d->progress != 0.0) {
@@ -319,6 +350,11 @@ void QQuickImageBase::requestFinished()
d->oldAutoTransform = autoTransform();
emitAutoTransformBaseChanged();
}
+ if (d->frameCount != d->pix.frameCount()) {
+ d->frameCount = d->pix.frameCount();
+ emit frameCountChanged();
+ }
+
update();
}
diff --git a/src/quick/items/qquickimagebase_p.h b/src/quick/items/qquickimagebase_p.h
index d8d0be9b8c..8cd59c8cea 100644
--- a/src/quick/items/qquickimagebase_p.h
+++ b/src/quick/items/qquickimagebase_p.h
@@ -68,6 +68,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickImageBase : public QQuickImplicitSizeItem
Q_PROPERTY(bool cache READ cache WRITE setCache NOTIFY cacheChanged)
Q_PROPERTY(QSize sourceSize READ sourceSize WRITE setSourceSize RESET resetSourceSize NOTIFY sourceSizeChanged)
Q_PROPERTY(bool mirror READ mirror WRITE setMirror NOTIFY mirrorChanged)
+ Q_PROPERTY(int currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY currentFrameChanged REVISION 14)
+ Q_PROPERTY(int frameCount READ frameCount NOTIFY frameCountChanged REVISION 14)
public:
QQuickImageBase(QQuickItem *parent=nullptr);
@@ -95,6 +97,11 @@ public:
virtual void setMirror(bool mirror);
bool mirror() const;
+ virtual void setCurrentFrame(int frame);
+ virtual int currentFrame() const;
+
+ virtual int frameCount() const;
+
virtual void setAutoTransform(bool transform);
bool autoTransform() const;
@@ -112,6 +119,8 @@ Q_SIGNALS:
void asynchronousChanged();
void cacheChanged();
void mirrorChanged();
+ Q_REVISION(14) void currentFrameChanged();
+ Q_REVISION(14) void frameCountChanged();
protected:
virtual void load();
diff --git a/src/quick/items/qquickimagebase_p_p.h b/src/quick/items/qquickimagebase_p_p.h
index 1b771166a2..88e18ba32e 100644
--- a/src/quick/items/qquickimagebase_p_p.h
+++ b/src/quick/items/qquickimagebase_p_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -68,6 +68,8 @@ public:
: status(QQuickImageBase::Null),
progress(0.0),
devicePixelRatio(1.0),
+ currentFrame(0),
+ frameCount(0),
async(false),
cache(true),
mirror(false),
@@ -85,6 +87,8 @@ public:
QSize oldSourceSize;
qreal devicePixelRatio;
QQuickImageProviderOptions providerOptions;
+ int currentFrame;
+ int frameCount;
bool async : 1;
bool cache : 1;
bool mirror: 1;
diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h
index ad9bab2a90..394a5adb8c 100644
--- a/src/quick/items/qquickitem.h
+++ b/src/quick/items/qquickitem.h
@@ -318,7 +318,7 @@ public:
void setKeepTouchGrab(bool);
// implemented in qquickitemgrabresult.cpp
- Q_REVISION(2) Q_INVOKABLE bool grabToImage(const QJSValue &callback, const QSize &targetSize = QSize());
+ Q_REVISION(4) Q_INVOKABLE bool grabToImage(const QJSValue &callback, const QSize &targetSize = QSize());
QSharedPointer<QQuickItemGrabResult> grabToImage(const QSize &targetSize = QSize());
Q_INVOKABLE virtual bool contains(const QPointF &point) const;
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 8aa259a7b6..6db664f705 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -245,28 +245,28 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickTextEdit,1>(uri,2,1,"TextEdit");
qmlRegisterType<QQuickTextInput>(uri,major,minor,"TextInput");
qmlRegisterType<QQuickTextInput,2>(uri,2,2,"TextInput");
- qmlRegisterType<QQuickTextInput,3>(uri,2,4,"TextInput");
- qmlRegisterType<QQuickItemGrabResult>();
+ qmlRegisterType<QQuickTextInput,4>(uri,2,4,"TextInput");
+ qmlRegisterAnonymousType<QQuickItemGrabResult>(uri, major);
#if QT_CONFIG(quick_shadereffect)
- qmlRegisterType<QQuickItemLayer>();
-#endif
- qmlRegisterType<QQuickAnchors>();
- qmlRegisterType<QQuickKeyEvent>();
- qmlRegisterType<QQuickMouseEvent>();
- qmlRegisterType<QQuickWheelEvent>();
- qmlRegisterType<QQuickCloseEvent>();
- qmlRegisterType<QQuickTransform>();
+ qmlRegisterAnonymousType<QQuickItemLayer>(uri, major);
+#endif
+ qmlRegisterAnonymousType<QQuickAnchors>(uri, major);
+ qmlRegisterAnonymousType<QQuickKeyEvent>(uri, major);
+ qmlRegisterAnonymousType<QQuickMouseEvent>(uri, major);
+ qmlRegisterAnonymousType<QQuickWheelEvent>(uri, major);
+ qmlRegisterAnonymousType<QQuickCloseEvent>(uri, major);
+ qmlRegisterAnonymousType<QQuickTransform>(uri, major);
#if QT_CONFIG(quick_path)
- qmlRegisterType<QQuickPathElement>();
- qmlRegisterType<QQuickCurve>();
+ qmlRegisterAnonymousType<QQuickPathElement>(uri, major);
+ qmlRegisterAnonymousType<QQuickCurve>(uri, major);
#endif
- qmlRegisterType<QQuickScaleGrid>();
- qmlRegisterType<QQuickTextLine>();
- qmlRegisterType<QQuickPen>();
- qmlRegisterType<QQuickFlickableVisibleArea>();
+ qmlRegisterAnonymousType<QQuickScaleGrid>(uri, major);
+ qmlRegisterAnonymousType<QQuickTextLine>(uri, major);
+ qmlRegisterAnonymousType<QQuickPen>(uri, major);
+ qmlRegisterAnonymousType<QQuickFlickableVisibleArea>(uri, major);
qRegisterMetaType<QQuickAnchorLine>("QQuickAnchorLine");
- qmlRegisterType<QQuickTextDocument>();
+ qmlRegisterAnonymousType<QQuickTextDocument>(uri, major);
qmlRegisterUncreatableType<QQuickKeyNavigationAttached>(uri,major,minor,"KeyNavigation",QQuickKeyNavigationAttached::tr("KeyNavigation is only available via attached properties"));
@@ -278,7 +278,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickPinchArea>(uri,major,minor,"PinchArea");
qmlRegisterType<QQuickPinch>(uri,major,minor,"Pinch");
- qmlRegisterType<QQuickPinchEvent>();
+ qmlRegisterAnonymousType<QQuickPinchEvent>(uri, major);
#if QT_CONFIG(quick_shadereffect)
qmlRegisterType<QQuickShaderEffectSource>("QtQuick", 2, 0, "ShaderEffectSource");
@@ -301,7 +301,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickParentChange>(uri, major, minor,"ParentChange");
qmlRegisterType<QQuickAnchorChanges>(uri, major, minor,"AnchorChanges");
- qmlRegisterType<QQuickAnchorSet>();
+ qmlRegisterAnonymousType<QQuickAnchorSet>(uri, major);
qmlRegisterType<QQuickAnchorAnimation>(uri, major, minor,"AnchorAnimation");
qmlRegisterType<QQuickParentAnimation>(uri, major, minor,"ParentAnimation");
#if QT_CONFIG(quick_path)
@@ -311,8 +311,8 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
#if QT_CONFIG(quick_draganddrop)
qmlRegisterType<QQuickDropArea>("QtQuick", 2, 0, "DropArea");
- qmlRegisterType<QQuickDropEvent>();
- qmlRegisterType<QQuickDropAreaDrag>();
+ qmlRegisterAnonymousType<QQuickDropEvent>(uri, 2);
+ qmlRegisterAnonymousType<QQuickDropAreaDrag>(uri, 2);
qmlRegisterUncreatableType<QQuickDrag>("QtQuick", 2, 0, "Drag", QQuickDragAttached::tr("Drag is only available via attached properties"));
#endif
@@ -333,7 +333,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
const char *itemViewName = "ItemView";
const QString itemViewMessage = QQuickItemView::tr("ItemView is an abstract base class");
qmlRegisterUncreatableType<QQuickItemView, 1>(uri, 2, 1, itemViewName, itemViewMessage);
- qmlRegisterUncreatableType<QQuickItemView, 2>(uri, 2, 3, itemViewName, itemViewMessage);
+ qmlRegisterUncreatableType<QQuickItemView, 3>(uri, 2, 3, itemViewName, itemViewMessage);
#endif
#if QT_CONFIG(quick_listview)
qmlRegisterType<QQuickListView, 1>(uri, 2, 1, "ListView");
@@ -348,23 +348,23 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickText, 3>(uri, 2, 3, "Text");
qmlRegisterType<QQuickTextEdit, 3>(uri, 2, 3, "TextEdit");
- qmlRegisterType<QQuickImage, 1>(uri, 2, 3,"Image");
+ qmlRegisterType<QQuickImage, 3>(uri, 2, 3,"Image");
- qmlRegisterType<QQuickItem, 2>(uri, 2, 4, "Item");
+ qmlRegisterType<QQuickItem, 4>(uri, 2, 4, "Item");
#if QT_CONFIG(quick_listview)
- qmlRegisterType<QQuickListView, 2>(uri, 2, 4, "ListView");
+ qmlRegisterType<QQuickListView, 4>(uri, 2, 4, "ListView");
#endif
- qmlRegisterType<QQuickMouseArea, 1>(uri, 2, 4, "MouseArea");
+ qmlRegisterType<QQuickMouseArea, 4>(uri, 2, 4, "MouseArea");
#if QT_CONFIG(quick_shadereffect)
- qmlRegisterType<QQuickShaderEffect, 1>(uri, 2, 4, "ShaderEffect");
+ qmlRegisterType<QQuickShaderEffect, 4>(uri, 2, 4, "ShaderEffect");
#endif
#if QT_CONFIG(opengl)
qmlRegisterUncreatableType<QQuickOpenGLInfo>(uri, 2, 4,"OpenGLInfo", QQuickOpenGLInfo::tr("OpenGLInfo is only available via attached properties"));
#endif
- qmlRegisterType<QQuickPinchArea, 1>(uri, 2, 5,"PinchArea");
- qmlRegisterType<QQuickImage, 2>(uri, 2, 5,"Image");
- qmlRegisterType<QQuickMouseArea, 2>(uri, 2, 5, "MouseArea");
+ qmlRegisterType<QQuickPinchArea, 5>(uri, 2, 5,"PinchArea");
+ qmlRegisterType<QQuickImage, 5>(uri, 2, 5,"Image");
+ qmlRegisterType<QQuickMouseArea, 5>(uri, 2, 5, "MouseArea");
qmlRegisterType<QQuickText, 6>(uri, 2, 6, "Text");
qmlRegisterType<QQuickTextEdit, 6>(uri, 2, 6, "TextEdit");
@@ -380,7 +380,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterUncreatableType<QQuickEnterKeyAttached, 6>(uri, 2, 6, "EnterKey",
QQuickEnterKeyAttached::tr("EnterKey is only available via attached properties"));
#if QT_CONFIG(quick_shadereffect)
- qmlRegisterType<QQuickShaderEffectSource, 1>(uri, 2, 6, "ShaderEffectSource");
+ qmlRegisterType<QQuickShaderEffectSource, 6>(uri, 2, 6, "ShaderEffectSource");
#endif
qmlRegisterType<QQuickItem, 7>(uri, 2, 7, "Item");
@@ -410,7 +410,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickMouseArea, 9>(uri, 2, 9, "MouseArea");
#if QT_CONFIG(quick_path)
- qmlRegisterType<QQuickPathArc, 2>(uri, 2, 9, "PathArc");
+ qmlRegisterType<QQuickPathArc, 9>(uri, 2, 9, "PathArc");
qmlRegisterType<QQuickPathMove>(uri, 2, 9, "PathMove");
#endif
@@ -425,7 +425,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
#endif
#if QT_CONFIG(quick_shadereffect)
- qmlRegisterType<QQuickShaderEffectSource, 2>(uri, 2, 9, "ShaderEffectSource");
+ qmlRegisterType<QQuickShaderEffectSource, 9>(uri, 2, 9, "ShaderEffectSource");
#endif
qmlRegisterType<QQuickFlickable, 10>(uri, 2, 10, "Flickable");
@@ -479,7 +479,11 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
#if QT_CONFIG(quick_itemview)
qmlRegisterUncreatableType<QQuickItemView, 13>(uri, 2, 13, itemViewName, itemViewMessage);
+#endif
+#if QT_CONFIG(quick_pathview)
qmlRegisterType<QQuickPathView, 13>(uri, 2, 13, "PathView");
+#endif
+#if QT_CONFIG(quick_gridview)
qmlRegisterType<QQuickGridView, 13>(uri, 2, 13, "GridView");
#endif
#if QT_CONFIG(quick_tableview)
@@ -488,6 +492,10 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
#if QT_CONFIG(wheelevent)
qmlRegisterType<QQuickWheelHandler>(uri, 2, 14, "WheelHandler");
#endif
+ qmlRegisterUncreatableType<QQuickImageBase, 14>(uri, 2, 14, "ImageBase",
+ QQuickPointerHandler::tr("ImageBase is an abstract base class"));
+ qmlRegisterType<QQuickImage, 14>(uri, 2, 14, "Image");
+ qmlRegisterType<QQuickDragHandler, 14>(uri, 2, 14, "DragHandler");
}
static void initResources()
diff --git a/src/quick/items/qquickitemview_p.h b/src/quick/items/qquickitemview_p.h
index 0a0da587b4..66e09f9ed1 100644
--- a/src/quick/items/qquickitemview_p.h
+++ b/src/quick/items/qquickitemview_p.h
@@ -81,8 +81,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickItemView : public QQuickFlickable
Q_PROPERTY(bool keyNavigationWraps READ isWrapEnabled WRITE setWrapEnabled NOTIFY keyNavigationWrapsChanged)
Q_PROPERTY(bool keyNavigationEnabled READ isKeyNavigationEnabled WRITE setKeyNavigationEnabled NOTIFY keyNavigationEnabledChanged REVISION 7)
Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
- Q_PROPERTY(int displayMarginBeginning READ displayMarginBeginning WRITE setDisplayMarginBeginning NOTIFY displayMarginBeginningChanged REVISION 2)
- Q_PROPERTY(int displayMarginEnd READ displayMarginEnd WRITE setDisplayMarginEnd NOTIFY displayMarginEndChanged REVISION 2)
+ Q_PROPERTY(int displayMarginBeginning READ displayMarginBeginning WRITE setDisplayMarginBeginning NOTIFY displayMarginBeginningChanged REVISION 3)
+ Q_PROPERTY(int displayMarginEnd READ displayMarginEnd WRITE setDisplayMarginEnd NOTIFY displayMarginEndChanged REVISION 3)
Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged)
Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged)
diff --git a/src/quick/items/qquicklistview_p.h b/src/quick/items/qquicklistview_p.h
index 9a9b325b1e..f2bab9e018 100644
--- a/src/quick/items/qquicklistview_p.h
+++ b/src/quick/items/qquicklistview_p.h
@@ -126,8 +126,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickListView : public QQuickItemView
Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged)
- Q_PROPERTY(HeaderPositioning headerPositioning READ headerPositioning WRITE setHeaderPositioning NOTIFY headerPositioningChanged REVISION 2)
- Q_PROPERTY(FooterPositioning footerPositioning READ footerPositioning WRITE setFooterPositioning NOTIFY footerPositioningChanged REVISION 2)
+ Q_PROPERTY(HeaderPositioning headerPositioning READ headerPositioning WRITE setHeaderPositioning NOTIFY headerPositioningChanged REVISION 4)
+ Q_PROPERTY(FooterPositioning footerPositioning READ footerPositioning WRITE setFooterPositioning NOTIFY footerPositioningChanged REVISION 4)
Q_CLASSINFO("DefaultProperty", "data")
@@ -188,8 +188,8 @@ Q_SIGNALS:
void highlightResizeVelocityChanged();
void highlightResizeDurationChanged();
void snapModeChanged();
- Q_REVISION(2) void headerPositioningChanged();
- Q_REVISION(2) void footerPositioningChanged();
+ Q_REVISION(4) void headerPositioningChanged();
+ Q_REVISION(4) void footerPositioningChanged();
protected:
void viewportMoved(Qt::Orientations orient) override;
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index bce7ec718b..a8f09dc8be 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -899,7 +899,7 @@ void QQuickMouseArea::wheelEvent(QWheelEvent *event)
}
QQuickWheelEvent &we = d->quickWheelEvent;
- we.reset(event->posF().x(), event->posF().y(), event->angleDelta(), event->pixelDelta(),
+ we.reset(event->position().x(), event->position().y(), event->angleDelta(), event->pixelDelta(),
event->buttons(), event->modifiers(), event->inverted());
we.setAccepted(d->isWheelConnected());
emit wheel(&we);
diff --git a/src/quick/items/qquickmousearea_p.h b/src/quick/items/qquickmousearea_p.h
index 76e5c98b35..0e01fa7915 100644
--- a/src/quick/items/qquickmousearea_p.h
+++ b/src/quick/items/qquickmousearea_p.h
@@ -71,7 +71,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickMouseArea : public QQuickItem
Q_PROPERTY(bool containsMouse READ hovered NOTIFY hoveredChanged)
Q_PROPERTY(bool pressed READ pressed NOTIFY pressedChanged)
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
- Q_PROPERTY(bool scrollGestureEnabled READ isScrollGestureEnabled WRITE setScrollGestureEnabled NOTIFY scrollGestureEnabledChanged REVISION 2)
+ Q_PROPERTY(bool scrollGestureEnabled READ isScrollGestureEnabled WRITE setScrollGestureEnabled NOTIFY scrollGestureEnabledChanged REVISION 5)
Q_PROPERTY(Qt::MouseButtons pressedButtons READ pressedButtons NOTIFY pressedButtonsChanged)
Q_PROPERTY(Qt::MouseButtons acceptedButtons READ acceptedButtons WRITE setAcceptedButtons NOTIFY acceptedButtonsChanged)
Q_PROPERTY(bool hoverEnabled READ hoverEnabled WRITE setHoverEnabled NOTIFY hoverEnabledChanged)
@@ -83,7 +83,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickMouseArea : public QQuickItem
#if QT_CONFIG(cursor)
Q_PROPERTY(Qt::CursorShape cursorShape READ cursorShape WRITE setCursorShape RESET unsetCursor NOTIFY cursorShapeChanged)
#endif
- Q_PROPERTY(bool containsPress READ containsPress NOTIFY containsPressChanged REVISION 1)
+ Q_PROPERTY(bool containsPress READ containsPress NOTIFY containsPressChanged REVISION 4)
Q_PROPERTY(int pressAndHoldInterval READ pressAndHoldInterval WRITE setPressAndHoldInterval NOTIFY pressAndHoldIntervalChanged RESET resetPressAndHoldInterval REVISION 9)
public:
@@ -134,7 +134,7 @@ Q_SIGNALS:
void hoveredChanged();
void pressedChanged();
void enabledChanged();
- Q_REVISION(2) void scrollGestureEnabledChanged();
+ Q_REVISION(5) void scrollGestureEnabledChanged();
void pressedButtonsChanged();
void acceptedButtonsChanged();
void hoverEnabledChanged();
@@ -156,7 +156,7 @@ Q_SIGNALS:
void entered();
void exited();
void canceled();
- Q_REVISION(1) void containsPressChanged();
+ Q_REVISION(4) void containsPressChanged();
Q_REVISION(9) void pressAndHoldIntervalChanged();
protected:
diff --git a/src/quick/items/qquickpincharea_p.h b/src/quick/items/qquickpincharea_p.h
index 8eff53e6dc..cf21555823 100644
--- a/src/quick/items/qquickpincharea_p.h
+++ b/src/quick/items/qquickpincharea_p.h
@@ -59,7 +59,7 @@ class Q_AUTOTEST_EXPORT QQuickPinch : public QObject
{
Q_OBJECT
- Q_PROPERTY(QQuickItem *target READ target WRITE setTarget RESET resetTarget)
+ Q_PROPERTY(QQuickItem *target READ target WRITE setTarget RESET resetTarget NOTIFY targetChanged)
Q_PROPERTY(qreal minimumScale READ minimumScale WRITE setMinimumScale NOTIFY minimumScaleChanged)
Q_PROPERTY(qreal maximumScale READ maximumScale WRITE setMaximumScale NOTIFY maximumScaleChanged)
Q_PROPERTY(qreal minimumRotation READ minimumRotation WRITE setMinimumRotation NOTIFY minimumRotationChanged)
@@ -283,7 +283,7 @@ Q_SIGNALS:
void pinchStarted(QQuickPinchEvent *pinch);
void pinchUpdated(QQuickPinchEvent *pinch);
void pinchFinished(QQuickPinchEvent *pinch);
- Q_REVISION(1) void smartZoom(QQuickPinchEvent *pinch);
+ Q_REVISION(5) void smartZoom(QQuickPinchEvent *pinch);
protected:
bool childMouseEventFilter(QQuickItem *i, QEvent *e) override;
diff --git a/src/quick/items/qquickscreen_p.h b/src/quick/items/qquickscreen_p.h
index e9db07d14c..10e524e4a0 100644
--- a/src/quick/items/qquickscreen_p.h
+++ b/src/quick/items/qquickscreen_p.h
@@ -83,8 +83,8 @@ class Q_AUTOTEST_EXPORT QQuickScreenInfo : public QObject
// TODO Qt 6 Remove this orientation -> incomplete device orientation -> better use OrientationSensor
Q_PROPERTY(Qt::ScreenOrientation orientation READ orientation NOTIFY orientationChanged)
- Q_PROPERTY(int virtualX READ virtualX NOTIFY virtualXChanged REVISION 1)
- Q_PROPERTY(int virtualY READ virtualY NOTIFY virtualYChanged REVISION 1)
+ Q_PROPERTY(int virtualX READ virtualX NOTIFY virtualXChanged REVISION 3)
+ Q_PROPERTY(int virtualY READ virtualY NOTIFY virtualYChanged REVISION 3)
public:
QQuickScreenInfo(QObject *parent = nullptr, QScreen *wrappedScreen = nullptr);
@@ -121,8 +121,8 @@ Q_SIGNALS:
void devicePixelRatioChanged();
void primaryOrientationChanged();
void orientationChanged();
- Q_REVISION(1) void virtualXChanged();
- Q_REVISION(1) void virtualYChanged();
+ Q_REVISION(3) void virtualXChanged();
+ Q_REVISION(3) void virtualYChanged();
protected:
QPointer<QScreen> m_screen;
diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h
index c5bddc40d2..6e2f35882b 100644
--- a/src/quick/items/qquickshadereffect_p.h
+++ b/src/quick/items/qquickshadereffect_p.h
@@ -74,7 +74,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffect : public QQuickItem
Q_PROPERTY(CullMode cullMode READ cullMode WRITE setCullMode NOTIFY cullModeChanged)
Q_PROPERTY(QString log READ log NOTIFY logChanged)
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
- Q_PROPERTY(bool supportsAtlasTextures READ supportsAtlasTextures WRITE setSupportsAtlasTextures NOTIFY supportsAtlasTexturesChanged REVISION 1)
+ Q_PROPERTY(bool supportsAtlasTextures READ supportsAtlasTextures WRITE setSupportsAtlasTextures NOTIFY supportsAtlasTexturesChanged REVISION 4)
public:
enum CullMode {
diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h
index d5bb33902a..d612d1179f 100644
--- a/src/quick/items/qquickshadereffectsource_p.h
+++ b/src/quick/items/qquickshadereffectsource_p.h
@@ -87,8 +87,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectSource : public QQuickItem, publi
Q_PROPERTY(bool hideSource READ hideSource WRITE setHideSource NOTIFY hideSourceChanged)
Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged)
Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged)
- Q_PROPERTY(TextureMirroring textureMirroring READ textureMirroring WRITE setTextureMirroring NOTIFY textureMirroringChanged REVISION 1)
- Q_PROPERTY(int samples READ samples WRITE setSamples NOTIFY samplesChanged REVISION 2)
+ Q_PROPERTY(TextureMirroring textureMirroring READ textureMirroring WRITE setTextureMirroring NOTIFY textureMirroringChanged REVISION 6)
+ Q_PROPERTY(int samples READ samples WRITE setSamples NOTIFY samplesChanged REVISION 9)
public:
enum WrapMode {
diff --git a/src/quick/items/qquicktextinput_p.h b/src/quick/items/qquicktextinput_p.h
index c46a2f8128..92f3aa62ce 100644
--- a/src/quick/items/qquicktextinput_p.h
+++ b/src/quick/items/qquicktextinput_p.h
@@ -93,7 +93,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextInput : public QQuickImplicitSizeItem
Q_PROPERTY(EchoMode echoMode READ echoMode WRITE setEchoMode NOTIFY echoModeChanged)
Q_PROPERTY(bool activeFocusOnPress READ focusOnPress WRITE setFocusOnPress NOTIFY activeFocusOnPressChanged)
Q_PROPERTY(QString passwordCharacter READ passwordCharacter WRITE setPasswordCharacter NOTIFY passwordCharacterChanged)
- Q_PROPERTY(int passwordMaskDelay READ passwordMaskDelay WRITE setPasswordMaskDelay RESET resetPasswordMaskDelay NOTIFY passwordMaskDelayChanged REVISION 3)
+ Q_PROPERTY(int passwordMaskDelay READ passwordMaskDelay WRITE setPasswordMaskDelay RESET resetPasswordMaskDelay NOTIFY passwordMaskDelayChanged REVISION 4)
Q_PROPERTY(QString displayText READ displayText NOTIFY displayTextChanged)
Q_PROPERTY(QString preeditText READ preeditText NOTIFY preeditTextChanged REVISION 7)
Q_PROPERTY(bool autoScroll READ autoScroll WRITE setAutoScroll NOTIFY autoScrollChanged)
@@ -268,7 +268,7 @@ public:
#if QT_CONFIG(im)
QVariant inputMethodQuery(Qt::InputMethodQuery property) const override;
- Q_REVISION(3) Q_INVOKABLE QVariant inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const;
+ Q_REVISION(4) Q_INVOKABLE QVariant inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const;
#endif
QRectF boundingRect() const override;
@@ -336,7 +336,7 @@ Q_SIGNALS:
void inputMaskChanged(const QString &inputMask);
void echoModeChanged(QQuickTextInput::EchoMode echoMode);
void passwordCharacterChanged();
- Q_REVISION(3) void passwordMaskDelayChanged(int delay);
+ Q_REVISION(4) void passwordMaskDelayChanged(int delay);
void displayTextChanged();
Q_REVISION(7) void preeditTextChanged();
void activeFocusOnPressChanged(bool activeFocusOnPress);
@@ -399,7 +399,7 @@ public Q_SLOTS:
void redo();
void insert(int position, const QString &text);
void remove(int start, int end);
- Q_REVISION(3) void ensureVisible(int position);
+ Q_REVISION(4) void ensureVisible(int position);
Q_REVISION(7) void clear();
private Q_SLOTS:
diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp
index 32478ba375..c4a8370f34 100644
--- a/src/quick/items/qquicktextnodeengine.cpp
+++ b/src/quick/items/qquicktextnodeengine.cpp
@@ -477,7 +477,7 @@ void QQuickTextNodeEngine::addTextObject(const QTextBlock &block, const QPointF
}
qreal ascent;
- QTextLine line = block.layout()->lineForTextPosition(pos);
+ QTextLine line = block.layout()->lineForTextPosition(pos - block.position());
switch (format.verticalAlignment())
{
case QTextCharFormat::AlignTop:
diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp
index fa9b44aa22..9998dc3605 100644
--- a/src/quick/items/qquickview.cpp
+++ b/src/quick/items/qquickview.cpp
@@ -240,6 +240,22 @@ void QQuickView::setSource(const QUrl& url)
}
/*!
+ Sets the initial properties with which the QML component gets initialized after
+ calling \l QQuickView::setSource.
+
+
+ Note that you can only use this function to initialize toplevel properties.
+
+ \sa QQmlComponent::createWithInitialProperties
+ \since 5.14
+*/
+void QQuickView::setInitialProperties(const QVariantMap &initialProperties)
+{
+ Q_D(QQuickView);
+ d->initialProperties = initialProperties;
+}
+
+/*!
\internal
Set the source \a url, \a component and content \a item (root of the QML object hierarchy) directly.
@@ -471,7 +487,7 @@ void QQuickView::continueExecute()
return;
}
- QObject *obj = d->component->create();
+ QObject *obj = d->initialProperties.empty() ? d->component->create() : d->component->createWithInitialProperties(d->initialProperties);
if (d->component->isError()) {
const QList<QQmlError> errorList = d->component->errors();
diff --git a/src/quick/items/qquickview.h b/src/quick/items/qquickview.h
index ecae25e90b..4122fcac79 100644
--- a/src/quick/items/qquickview.h
+++ b/src/quick/items/qquickview.h
@@ -88,6 +88,7 @@ public:
public Q_SLOTS:
void setSource(const QUrl&);
+ void setInitialProperties(const QVariantMap &initialProperties);
void setContent(const QUrl& url, QQmlComponent *component, QObject *item);
Q_SIGNALS:
diff --git a/src/quick/items/qquickview_p.h b/src/quick/items/qquickview_p.h
index 3f284c0519..b1ab8d8e8c 100644
--- a/src/quick/items/qquickview_p.h
+++ b/src/quick/items/qquickview_p.h
@@ -108,6 +108,8 @@ public:
QQuickView::ResizeMode resizeMode;
QSize initialSize;
QElapsedTimer frameTimer;
+
+ QVariantMap initialProperties;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index a208e135af..51bcdbf352 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -702,7 +702,7 @@ bool QQuickWindowPrivate::checkIfDoubleTapped(ulong newPressEventTimestamp, QPoi
if (touchMousePressTimestamp > 0) {
QPoint distanceBetweenPresses = newPressPos - touchMousePressPos;
- const int doubleTapDistance = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::TouchDoubleTapDistance).toInt();
+ const int doubleTapDistance = QGuiApplication::styleHints()->touchDoubleTapDistance();
doubleClicked = (qAbs(distanceBetweenPresses.x()) <= doubleTapDistance) && (qAbs(distanceBetweenPresses.y()) <= doubleTapDistance);
if (doubleClicked) {
@@ -4224,7 +4224,7 @@ QQmlIncubationController *QQuickWindow::incubationController() const
When not running with the RHI (and using OpenGL directly), the signal is
emitted after the renderer has cleared the render target. This makes it
- possible to create appliations that function identically both with and
+ possible to create applications that function identically both with and
without the RHI.
\note Resource updates (uploads, copies) typically cannot be enqueued from
@@ -4255,7 +4255,7 @@ QQmlIncubationController *QQuickWindow::incubationController() const
When not running with the RHI (and using OpenGL directly), the signal is
emitted after the renderer has finished its rendering, but before
- afterRendering(). This makes it possible to create appliations that
+ afterRendering(). This makes it possible to create applications that
function identically both with and without the RHI.
\note Resource updates (uploads, copies) typically cannot be enqueued from
@@ -4450,7 +4450,8 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateText
\note This function only has an effect when using the default OpenGL scene graph
adaptation.
- \note This function has no effect when running on the RHI graphics abstraction.
+ \note This function has no effect when running on the RHI graphics
+ abstraction. Use createTextureFromNativeObject() instead.
\sa sceneGraphInitialized(), QSGTexture
*/
@@ -4458,19 +4459,120 @@ QSGTexture *QQuickWindow::createTextureFromId(uint id, const QSize &size, Create
{
#if QT_CONFIG(opengl)
Q_D(const QQuickWindow);
- if (!d->rhi && openglContext()) {
- QSGPlainTexture *texture = new QSGPlainTexture();
- texture->setTextureId(id);
+ if (!d->rhi) {
+ if (openglContext()) {
+ QSGPlainTexture *texture = new QSGPlainTexture();
+ texture->setTextureId(id);
+ texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
+ texture->setOwnsTexture(options & TextureOwnsGLTexture);
+ texture->setTextureSize(size);
+ return texture;
+ }
+ } else {
+ qWarning("createTextureFromId() must not be called when running on the RHI. "
+ "Use createTextureFromNativeObject() instead.");
+ }
+#else
+ Q_UNUSED(id)
+ Q_UNUSED(size)
+ Q_UNUSED(options)
+#endif
+ return nullptr;
+}
+
+/*!
+ \enum QQuickWindow::NativeObjectType
+ \since 5.14
+
+ Specifies the type of the native object passed to functions such as
+ createTextureFromNativeObject().
+
+ \value NativeObjectTexture The native object is a 2D texture (OpenGL,
+ Direct3D 11, Metal) or image (Vulkan).
+ */
+
+/*!
+ Creates a new QSGTexture object from an existing native object.
+
+ The native object is wrapped, but not owned, by the resulting QSGTexture.
+ The caller of the function is responsible for deleting the returned
+ QSGTexture, but that will not destroy the underlying native object.
+
+ \a type specifies the type of the object. In practice the type is
+ NativeObjectTexture, indicating that the native object is a texture or
+ image of the underlying graphics API. Other types may be introduced in the
+ future.
+
+ This function is currently suitable for 2D RGBA textures only.
+
+ Unlike createTextureFromId(), this function supports both direct OpenGL
+ usage and the RHI abstracted rendering path.
+
+ \warning This function will return null if the scenegraph has not yet been
+ initialized.
+
+ Use \a options to customize the texture attributes. Only the
+ TextureHasAlphaChannel and TextureHasMipmaps are taken into account here.
+
+ \warning Unlike createTextureFromId(), this function never takes ownership
+ of the native object, and the TextureOwnsGLTexture flag is ignored.
+
+ \a size specifies the size in pixels.
+
+ \a nativeObjectPtr is a pointer to the native object handle. With OpenGL,
+ the native handle is a GLuint value, so \a nativeObjectPtr is then a
+ pointer to a GLuint. With Vulkan, the native handle is a VkImage, so \a
+ nativeObjectPtr is a pointer to a VkImage. With Direct3D 11 and Metal \a
+ nativeObjectPtr is a pointer to a ID3D11Texture2D or MTLTexture pointer.
+
+ \note Pay attention to the fact that \a nativeObjectPtr is always a pointer
+ to the native texture handle type, even if the native type itself is a
+ pointer.
+
+ \a nativeLayout is only used for APIs like Vulkan. When applicable, it must
+ specify the current image layout, such as, a VkImageLayout value.
+
+ \sa sceneGraphInitialized(), QSGTextures
+
+ \since 5.14
+ */
+QSGTexture *QQuickWindow::createTextureFromNativeObject(NativeObjectType type,
+ const void *nativeObjectPtr,
+ int nativeLayout,
+ const QSize &size,
+ CreateTextureOptions options) const
+{
+ if (type != NativeObjectTexture) {
+ qWarning("createTextureFromNativeObject: only textures are supported");
+ return nullptr;
+ }
+
+#if QT_CONFIG(opengl) /* || QT_CONFIG(vulkan) || defined(Q_OS_WIN) || defined(Q_OS_DARWIN) */
+ Q_D(const QQuickWindow);
+ if (d->rhi) {
+ QSGPlainTexture *texture = new QSGPlainTexture;
+ texture->setTextureFromNativeObject(d->rhi, type, nativeObjectPtr, nativeLayout,
+ size, options.testFlag(TextureHasMipmaps));
+ texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
+ // note that the QRhiTexture does not (and cannot) own the native object
+ texture->setOwnsTexture(true); // texture meaning the QRhiTexture here, not the native object
+ texture->setTextureSize(size);
+ return texture;
+ } else if (openglContext()) {
+ QSGPlainTexture *texture = new QSGPlainTexture;
+ texture->setTextureId(*reinterpret_cast<const uint *>(nativeObjectPtr));
texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
texture->setOwnsTexture(options & TextureOwnsGLTexture);
texture->setTextureSize(size);
return texture;
}
#else
- Q_UNUSED(id)
- Q_UNUSED(size)
- Q_UNUSED(options)
+ Q_UNUSED(nativeObjectPtr);
+ Q_UNUSED(nativeLayout);
+ Q_UNUSED(size);
+ Q_UNUSED(options);
#endif
+
return nullptr;
}
@@ -4666,6 +4768,11 @@ const QQuickWindow::GraphicsStateInfo *QQuickWindow::graphicsStateInfo()
beginExternalCommands() and endExternalCommands() together provide a
replacement for resetOpenGLState().
+ Calling this function and endExternalCommands() is not necessary within the
+ \l{QSGRenderNode::render()}{render()} implementation of a QSGRenderNode
+ because the scene graph performs the necessary steps implicitly for render
+ nodes.
+
\note This function has no effect when the scene graph is using OpenGL
directly and the RHI graphics abstraction layer is not in use. Refer to
resetOpenGLState() in that case.
@@ -4704,6 +4811,11 @@ void QQuickWindow::beginExternalCommands()
beginExternalCommands() and endExternalCommands() together provide a
replacement for resetOpenGLState().
+ Calling this function and beginExternalCommands() is not necessary within the
+ \l{QSGRenderNode::render()}{render()} implementation of a QSGRenderNode
+ because the scene graph performs the necessary steps implicitly for render
+ nodes.
+
\note This function has no effect when the scene graph is using OpenGL
directly and the RHI graphics abstraction layer is not in use. Refer to
resetOpenGLState() in that case.
diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h
index ab3046611f..9dbff88f0d 100644
--- a/src/quick/items/qquickwindow.h
+++ b/src/quick/items/qquickwindow.h
@@ -109,6 +109,11 @@ public:
};
Q_ENUM(TextRenderType)
+ enum NativeObjectType {
+ NativeObjectTexture
+ };
+ Q_ENUM(NativeObjectType)
+
explicit QQuickWindow(QWindow *parent = nullptr);
explicit QQuickWindow(QQuickRenderControl *renderControl);
@@ -153,6 +158,11 @@ public:
QSGTexture *createTextureFromImage(const QImage &image) const;
QSGTexture *createTextureFromImage(const QImage &image, CreateTextureOptions options) const;
QSGTexture *createTextureFromId(uint id, const QSize &size, CreateTextureOptions options = CreateTextureOption()) const;
+ QSGTexture *createTextureFromNativeObject(NativeObjectType type,
+ const void *nativeObjectPtr,
+ int nativeLayout,
+ const QSize &size,
+ CreateTextureOptions options = CreateTextureOption()) const;
void setClearBeforeRendering(bool enabled);
bool clearBeforeRendering() const;
diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp
index 7b3874dbfe..4b2b8f498d 100644
--- a/src/quick/items/qquickwindowmodule.cpp
+++ b/src/quick/items/qquickwindowmodule.cpp
@@ -205,11 +205,11 @@ void QQuickWindowModule::defineModule()
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");
- qmlRegisterType<QQuickWindowQmlImpl,2>(uri, 2, 3, "Window");
+ qmlRegisterType<QQuickWindowQmlImpl,2>(uri, 2, 2, "Window");
+ qmlRegisterType<QQuickWindowQmlImpl,3>(uri, 2, 3, "Window");
qmlRegisterUncreatableType<QQuickScreen>(uri, 2, 0, "Screen", QStringLiteral("Screen can only be used via the attached property."));
- qmlRegisterUncreatableType<QQuickScreen,1>(uri, 2, 3, "Screen", QStringLiteral("Screen can only be used via the attached property."));
- qmlRegisterUncreatableType<QQuickScreenInfo,2>(uri, 2, 3, "ScreenInfo", QStringLiteral("ScreenInfo can only be used via the attached property."));
+ qmlRegisterUncreatableType<QQuickScreen,3>(uri, 2, 3, "Screen", QStringLiteral("Screen can only be used via the attached property."));
+ qmlRegisterUncreatableType<QQuickScreenInfo,3>(uri, 2, 3, "ScreenInfo", QStringLiteral("ScreenInfo can only be used via the attached property."));
qmlRegisterUncreatableType<QQuickScreenInfo,10>(uri, 2, 10, "ScreenInfo", QStringLiteral("ScreenInfo can only be used via the attached property."));
qmlRegisterRevision<QWindow,13>(uri, 2, 13);
qmlRegisterRevision<QQuickWindow,13>(uri, 2, 13);
diff --git a/src/quick/items/qquickwindowmodule_p.h b/src/quick/items/qquickwindowmodule_p.h
index e7033e9b8d..1dcf1a1021 100644
--- a/src/quick/items/qquickwindowmodule_p.h
+++ b/src/quick/items/qquickwindowmodule_p.h
@@ -67,7 +67,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickWindowQmlImpl : public QQuickWindow, public Q
Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged)
Q_PROPERTY(Visibility visibility READ visibility WRITE setVisibility NOTIFY visibilityChanged)
- Q_PROPERTY(QObject *screen READ screen WRITE setScreen NOTIFY screenChanged REVISION 2)
+ Q_PROPERTY(QObject *screen READ screen WRITE setScreen NOTIFY screenChanged REVISION 3)
public:
QQuickWindowQmlImpl(QWindow *parent = nullptr);
@@ -83,7 +83,7 @@ public:
Q_SIGNALS:
void visibleChanged(bool arg);
void visibilityChanged(QWindow::Visibility visibility);
- Q_REVISION(2) void screenChanged();
+ Q_REVISION(3) void screenChanged();
protected:
void classBegin() override;
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp
index f8973af2fb..2d4dcd928d 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp
@@ -69,10 +69,6 @@ const QEvent::Type WM_Obscure = QEvent::Type(QEvent::User + 1);
// Passed from the RL to RT when GUI has been locked, waiting for sync.
const QEvent::Type WM_RequestSync = QEvent::Type(QEvent::User + 2);
-// Passed by the RT to itself to trigger another render pass. This is typically
-// a result of QQuickWindow::update().
-const QEvent::Type WM_RequestRepaint = QEvent::Type(QEvent::User + 3);
-
// Passed by the RL to the RT to maybe release resource if no windows are
// rendering.
const QEvent::Type WM_TryRelease = QEvent::Type(QEvent::User + 4);
@@ -353,13 +349,6 @@ bool QSGSoftwareRenderThread::event(QEvent *e)
return true;
}
- case WM_RequestRepaint:
- qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_RequestPaint");
- // When GUI posts this event, it is followed by a polishAndSync, so we
- // must not exit the event loop yet.
- pendingUpdate |= RepaintRequest;
- break;
-
default:
break;
}
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index 2cd9ee689b..a566a2bed6 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -2665,7 +2665,8 @@ void Renderer::updateClipState(const QSGClipNode *clipList, Batch *batch) // RHI
{
// Note: No use of the clip-related speparate m_current* vars is allowed
// here. All stored in batch->clipState instead. To collect state during
- // renderBatches(), m_currentClipState is used.
+ // the prepare steps, m_currentClipState is used. It should not be used in
+ // the render steps afterwards.
// The stenciling logic is slightly different from the legacy GL path as we
// cannot just randomly clear the stencil buffer. We now put all clip
@@ -3491,7 +3492,7 @@ void Renderer::updateMaterialDynamicData(ShaderManager::Shader *sms,
}
if (pd->textureBindingTable[binding] && pd->samplerBindingTable[binding]) {
- QRhiTexture *texture = pd->textureBindingTable[binding]->rhiTexture();
+ QRhiTexture *texture = QSGTexturePrivate::get(pd->textureBindingTable[binding])->rhiTexture();
// texture may be null if the update above failed for any reason,
// or if the QSGTexture chose to return null intentionally. This is
// valid and we still need to provide something to the shader.
@@ -4089,7 +4090,7 @@ void Renderer::renderBatches()
if (b->merged)
ok = prepareRenderMergedBatch(b, &renderBatch);
else if (b->isRenderNode)
- ok = false; // ###
+ ok = prepareRhiRenderNode(b, &renderBatch);
else
ok = prepareRenderUnmergedBatch(b, &renderBatch);
if (ok)
@@ -4120,7 +4121,7 @@ void Renderer::renderBatches()
if (renderBatch->batch->merged)
renderMergedBatch(renderBatch);
else if (renderBatch->batch->isRenderNode)
- Q_UNREACHABLE(); // ###
+ renderRhiRenderNode(renderBatch->batch);
else
renderUnmergedBatch(renderBatch);
}
@@ -4359,7 +4360,7 @@ struct RenderNodeState : public QSGRenderNode::RenderState
bool m_stencilEnabled;
};
-void Renderer::renderRenderNode(Batch *batch)
+void Renderer::renderRenderNode(Batch *batch) // legacy (GL-only)
{
if (Q_UNLIKELY(debug_render()))
qDebug() << " -" << batch << "rendernode";
@@ -4475,6 +4476,108 @@ void Renderer::renderRenderNode(Batch *batch)
glBindFramebuffer(GL_FRAMEBUFFER, prevFbo);
}
+bool Renderer::prepareRhiRenderNode(Batch *batch, PreparedRenderBatch *renderBatch) // split prepare-render (RHI only)
+{
+ if (Q_UNLIKELY(debug_render()))
+ qDebug() << " -" << batch << "rendernode";
+
+ Q_ASSERT(batch->first->isRenderNode);
+ RenderNodeElement *e = static_cast<RenderNodeElement *>(batch->first);
+
+ setActiveRhiShader(nullptr, nullptr);
+
+ QSGNode *clip = e->renderNode->parent();
+ QSGRenderNodePrivate *rd = QSGRenderNodePrivate::get(e->renderNode);
+ rd->m_clip_list = nullptr;
+ while (clip != rootNode()) {
+ if (clip->type() == QSGNode::ClipNodeType) {
+ rd->m_clip_list = static_cast<QSGClipNode *>(clip);
+ break;
+ }
+ clip = clip->parent();
+ }
+
+ updateClipState(rd->m_clip_list, batch);
+
+ renderBatch->batch = batch;
+ renderBatch->sms = nullptr;
+
+ return true;
+}
+
+void Renderer::renderRhiRenderNode(const Batch *batch) // split prepare-render (RHI only)
+{
+ if (batch->clipState.type & ClipState::StencilClip)
+ enqueueStencilDraw(batch);
+
+ RenderNodeElement *e = static_cast<RenderNodeElement *>(batch->first);
+ QSGRenderNodePrivate *rd = QSGRenderNodePrivate::get(e->renderNode);
+
+ QMatrix4x4 pm = projectionMatrix();
+ if (m_useDepthBuffer) {
+ pm(2, 2) = m_zRange;
+ pm(2, 3) = 1.0f - e->order * m_zRange;
+ }
+
+ RenderNodeState state;
+ state.m_projectionMatrix = &pm;
+ const std::array<int, 4> scissor = batch->clipState.scissor.scissor();
+ state.m_scissorRect = QRect(scissor[0], scissor[1], scissor[2], scissor[3]);
+ state.m_stencilValue = batch->clipState.stencilRef;
+ state.m_scissorEnabled = batch->clipState.type & ClipState::ScissorClip;
+ state.m_stencilEnabled = batch->clipState.type & ClipState::StencilClip;
+
+ QSGNode *xform = e->renderNode->parent();
+ QMatrix4x4 matrix;
+ QSGNode *root = rootNode();
+ if (e->root) {
+ matrix = qsg_matrixForRoot(e->root);
+ root = e->root->sgNode;
+ }
+ while (xform != root) {
+ if (xform->type() == QSGNode::TransformNodeType) {
+ matrix = matrix * static_cast<QSGTransformNode *>(xform)->combinedMatrix();
+ break;
+ }
+ xform = xform->parent();
+ }
+ rd->m_matrix = &matrix;
+
+ QSGNode *opacity = e->renderNode->parent();
+ rd->m_opacity = 1.0;
+ while (opacity != rootNode()) {
+ if (opacity->type() == QSGNode::OpacityNodeType) {
+ rd->m_opacity = static_cast<QSGOpacityNode *>(opacity)->combinedOpacity();
+ break;
+ }
+ opacity = opacity->parent();
+ }
+
+ const QSGRenderNode::StateFlags changes = e->renderNode->changedStates();
+
+ QRhiCommandBuffer *cb = commandBuffer();
+ cb->beginExternal();
+ e->renderNode->render(&state);
+ cb->endExternal();
+
+ rd->m_matrix = nullptr;
+ rd->m_clip_list = nullptr;
+
+ if ((changes & QSGRenderNode::ViewportState)
+ || (changes & QSGRenderNode::ScissorState))
+ {
+ // Reset both flags if either is reported as changed, since with the rhi
+ // it could be setViewport() that will record the resetting of the scissor.
+ m_pstate.viewportSet = false;
+ m_pstate.scissorSet = false;
+ }
+
+ // Do not bother with RenderTargetState. Where applicable, endExternal()
+ // ensures the correct target is rebound. For others (like Vulkan) it makes
+ // no sense since render() could not possibly do that on our command buffer
+ // which is in renderpass recording state.
+}
+
void Renderer::setCustomRenderMode(const QByteArray &mode)
{
if (mode.isEmpty())
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
index ea9dab244f..4e374522d4 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
@@ -817,6 +817,8 @@ private:
void enqueueStencilDraw(const Batch *batch);
const QMatrix4x4 &matrixForRoot(Node *node);
void renderRenderNode(Batch *batch);
+ bool prepareRhiRenderNode(Batch *batch, PreparedRenderBatch *renderBatch);
+ void renderRhiRenderNode(const Batch *batch);
void setActiveShader(QSGMaterialShader *program, ShaderManager::Shader *shader);
void setActiveRhiShader(QSGMaterialRhiShader *program, ShaderManager::Shader *shader);
diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.cpp b/src/quick/scenegraph/coreapi/qsgrendernode.cpp
index df3fa16a32..2892f2f966 100644
--- a/src/quick/scenegraph/coreapi/qsgrendernode.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrendernode.cpp
@@ -81,8 +81,10 @@ QSGRenderNodePrivate::QSGRenderNodePrivate()
}
/*!
- This function should return a mask where each bit represents graphics states changed by
- the \l render() function:
+ When the underlying rendering API is OpenGL, this function should return a
+ mask where each bit represents graphics states changed by the \l render()
+ function:
+
\list
\li DepthState - depth write mask, depth test enabled, depth comparison function
\li StencilState - stencil write masks, stencil test enabled, stencil operations,
@@ -95,6 +97,29 @@ QSGRenderNodePrivate::QSGRenderNodePrivate()
\li RenderTargetState - render target
\endlist
+ With APIs other than OpenGL, the only relevant values are the ones that
+ correspond to dynamic state changes recorded on the command list/buffer.
+ For example, RSSetViewports, RSSetScissorRects, OMSetBlendFactor,
+ OMSetStencilRef in case of D3D12, or vkCmdSetViewport, vkCmdSetScissor,
+ vkCmdSetBlendConstants, vkCmdSetStencilRef in case of Vulkan, and only when
+ such commands were added to the scenegraph's command list queried via the
+ QSGRendererInterface::CommandList resource enum. States set in pipeline
+ state objects do not need to be reported here. Similarly, draw call related
+ settings (pipeline states, descriptor sets, vertex or index buffer
+ bindings, root signature, descriptor heaps, etc.) are always set again by
+ the scenegraph so render() can freely change them.
+
+ \note RenderTargetState is no longer supported with APIs like Vulkan. This
+ is by nature. render() is invoked while the Qt Quick scenegraph's main
+ command buffer is recording a renderpass, so there is no possibility of
+ changing the target and starting another renderpass (on that command buffer
+ at least). Therefore returning a value with RenderTargetState set is not
+ sensible.
+
+ The software backend exposes its QPainter and saves and restores before and
+ after invoking render(). Therefore reporting any changed states from here
+ is not necessary.
+
The function is called by the renderer so it can reset the states after
rendering this node. This makes the implementation of render() simpler
since it does not have to query and restore these states.
@@ -102,19 +127,6 @@ QSGRenderNodePrivate::QSGRenderNodePrivate()
The default implementation returns 0, meaning no relevant state was changed
in render().
- With APIs other than OpenGL the relevant states are only those that are set
- via the command list (for example, OMSetRenderTargets, RSSetViewports,
- RSSetScissorRects, OMSetBlendFactor, OMSetStencilRef in case of D3D12), and
- only when such commands were added to the scenegraph's command list queried
- via the QSGRendererInterface::CommandList resource enum. States set in
- pipeline state objects do not need to be reported here. Similarly, draw
- call related settings (root signature, descriptor heaps, etc.) are always
- set again by the scenegraph so render() can freely change them.
-
- The software backend exposes its QPainter and saves and restores before and
- after invoking render(). Therefore reporting any changed states from here
- is not necessary.
-
\note This function may be called before render().
*/
QSGRenderNode::StateFlags QSGRenderNode::changedStates() const
@@ -149,18 +161,31 @@ QSGRenderNode::StateFlags QSGRenderNode::changedStates() const
QQuickFramebufferObject, QQuickWindow::beforeRendering(), or the
equivalents of those for APIs other than OpenGL.
- Clip information is calculated before the function is called, it is however
- not enabled. Implementations wishing to take clipping into account can set
- up scissoring or stencil based on the information in \a state. Some
- scenegraph backends, software in particular, use no scissor or stencil.
- There the clip region is provided as an ordinary QRegion.
+ \note QSGRenderNode can perform significantly better than texture-based
+ approaches (such as, QQuickFramebufferObject), especially on systems where
+ the fragment processing power is limited. This is because it avoids
+ rendering to a texture and then drawing a textured quad. Rather,
+ QSGRenderNode allows recording draw calls in line with the scenegraph's
+ other commands, avoiding an additional render target and the potentially
+ expensive texturing and blending.
+
+ Clip information is calculated before the function is called.
+ Implementations wishing to take clipping into account can set up scissoring
+ or stencil based on the information in \a state. The stencil buffer is
+ filled with the necessary clip shapes, but it is up to the implementation
+ to enable stencil testing.
+
+ Some scenegraph backends, software in particular, use no scissor or
+ stencil. There the clip region is provided as an ordinary QRegion.
+
+ With the legacy, direct OpenGL based renderer, the following states are set
+ on the render thread's context before this function is called:
- For OpenGL the following states are set on the render thread's context
- before this function is called:
\list
+ \li glColorMask(true, true, true, true)
\li glDepthMask(false)
\li glDisable(GL_DEPTH_TEST)
- \li glStencilFunc(GL_EQUAL, state.stencilValue, 0xff) depending on clip
+ \li glStencilFunc(GL_EQUAL, state.stencilValue, 0xff); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP) depending on clip
\li glScissor(state.scissorRect.x(), state.scissorRect.y(),
state.scissorRect.width(), state.scissorRect.height()) depending on clip
\li glEnable(GL_BLEND)
@@ -168,23 +193,42 @@ QSGRenderNode::StateFlags QSGRenderNode::changedStates() const
\li glDisable(GL_CULL_FACE)
\endlist
- States that are not listed above, but are included in \l StateFlags, can
+ States that are not listed above, but are covered by \l StateFlags, can
have arbitrary values.
+ \note There is no state set with other graphics APIs, considering that many
+ of them do not have a concept of the traditional OpenGL state machine.
+ Rather, it is up to the implementation to create pipeline state objects
+ with the desired blending, scissor, and stencil tests enabled. Note that
+ this also includes OpenGL via the RHI. New QSGRenderNode implementations
+ are recommended to set all scissor, stencil and blend state explicitly (as
+ shown in the above list), even if they are targeting OpenGL.
+
\l changedStates() should return which states this function changes. If a
state is not covered by \l StateFlags, the state should be set to the
default value according to the OpenGL specification. For other APIs, see
the documentation for changedStates() for more information.
- \note Depth writes are disabled when this function is called (for example,
- glDepthMask(false) in case of OpenGL). Enabling depth writes can lead to
- unexpected results, depending on the scenegraph backend in use, so nodes
- should avoid this.
+ \note Depth writes are disabled when this function is called
+ (glDepthMask(false) with OpenGL). Enabling depth writes can lead to
+ unexpected results, depending on the scenegraph backend in use and the
+ content in the scene, so exercise caution with this.
For APIs other than OpenGL, it will likely be necessary to query certain
API-specific resources (for example, the graphics device or the command
list/buffer to add the commands to). This is done via QSGRendererInterface.
+ Assume nothing about the pipelines and dynamic states bound on the command
+ list/buffer when this function is called.
+
+ With some graphics APIs it can be necessary to also connect to the
+ QQuickWindow::beforeRendering() signal, because that is emitted before
+ recording the beginning of a renderpass on the command buffer
+ (vkCmdBeginRenderPass with Vulkan, or starting to encode via
+ MTLRenderCommandEncoder in case of Metal). Recording copy operations cannot
+ be done inside render() with such APIs. Rather, do it in the slot connected
+ (with DirectConnection) to the beforeRendering signal.
+
\sa QSGRendererInterface, QQuickWindow::rendererInterface()
*/
@@ -335,7 +379,8 @@ QSGRenderNode::RenderState::~RenderState()
/*!
\fn const QMatrix4x4 *QSGRenderNode::RenderState::scissorRect() const
- \return the current scissor rectangle when clipping is active.
+ \return the current scissor rectangle when clipping is active. x and y are
+ the bottom left coordinates.
\note Be aware of the differences between graphics APIs: for some the
scissor rect is only active when scissoring is enabled (for example,
diff --git a/src/quick/scenegraph/coreapi/qsgtexture.cpp b/src/quick/scenegraph/coreapi/qsgtexture.cpp
index cfd0cb9f06..c47401e5c0 100644
--- a/src/quick/scenegraph/coreapi/qsgtexture.cpp
+++ b/src/quick/scenegraph/coreapi/qsgtexture.cpp
@@ -696,27 +696,6 @@ void QSGTexture::updateBindOptions(bool force) // legacy (GL-only)
}
/*!
- \return the QRhiTexture for this QSGTexture or null if there is none.
-
- Unlike textureId(), this function is not expected to create a new
- QRhiTexture in case there is none. Just return null in that case. The
- expectation towards the renderer is that a null texture leads to using a
- transparent, dummy texture instead.
-
- \note This function is only used when running the graphics API independent
- rendering path of the scene graph.
-
- \warning This function can only be called from the rendering thread.
-
- \since 5.14
- */
-QRhiTexture *QSGTexture::rhiTexture() const
-{
- Q_D(const QSGTexture);
- return d->rhiTexture();
-}
-
-/*!
Call this function to enqueue image upload operations to \a
resourceUpdates, in case there are any pending ones. When there is no new
data (for example, because there was no setImage() since the last call to
@@ -762,6 +741,23 @@ int QSGTexturePrivate::comparisonKey() const
return q->textureId(); // this is semantically wrong but at least compatible with existing, non-RHI-aware subclasses
}
+/*!
+ \internal
+
+ \return the QRhiTexture for this QSGTexture or null if there is none.
+
+ Unlike textureId(), this function is not expected to create a new
+ QRhiTexture in case there is none. Just return null in that case. The
+ expectation towards the renderer is that a null texture leads to using a
+ transparent, dummy texture instead.
+
+ \note This function is only used when running the graphics API independent
+ rendering path of the scene graph.
+
+ \warning This function can only be called from the rendering thread.
+
+ \since 5.14
+ */
QRhiTexture *QSGTexturePrivate::rhiTexture() const
{
return nullptr;
diff --git a/src/quick/scenegraph/coreapi/qsgtexture.h b/src/quick/scenegraph/coreapi/qsgtexture.h
index f2b0e902f3..4cd2a5cddd 100644
--- a/src/quick/scenegraph/coreapi/qsgtexture.h
+++ b/src/quick/scenegraph/coreapi/qsgtexture.h
@@ -113,7 +113,6 @@ public:
// ### Qt 6: make these virtual
int comparisonKey() const;
- QRhiTexture *rhiTexture() const;
void updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates);
// ### Qt 6: make this an argument for removedFromAtlas()
diff --git a/src/quick/scenegraph/coreapi/qsgtexture_p.h b/src/quick/scenegraph/coreapi/qsgtexture_p.h
index 1d248b0305..cb59d32012 100644
--- a/src/quick/scenegraph/coreapi/qsgtexture_p.h
+++ b/src/quick/scenegraph/coreapi/qsgtexture_p.h
@@ -83,9 +83,10 @@ public:
void resetDirtySamplerOptions();
bool hasDirtySamplerOptions() const;
+ virtual QRhiTexture *rhiTexture() const;
+
// ### Qt 6: these should be virtuals in the public class instead
virtual int comparisonKey() const; // ### Qt 6: pure virtual
- virtual QRhiTexture *rhiTexture() const;
virtual void updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates);
QRhiResourceUpdateBatch *workResourceUpdateBatch = nullptr; // ### Qt 6: remove
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
index db889c3102..8fc8c711c6 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -451,7 +451,9 @@ bool QSGTextMaskRhiShader::updateUniformData(const RenderState &state,
changed = true;
}
- if (updated || !oldMat || oldMat->texture()->rhiTexture() != mat->texture()->rhiTexture()) {
+ QRhiTexture *oldRtex = oldMat ? QSGTexturePrivate::get(oldMat->texture())->rhiTexture() : nullptr;
+ QRhiTexture *newRtex = QSGTexturePrivate::get(mat->texture())->rhiTexture();
+ if (updated || !oldMat || oldRtex != newRtex) {
const QVector2D textureScale = QVector2D(1.0f / mat->rhiGlyphCache()->width(),
1.0f / mat->rhiGlyphCache()->height());
memcpy(buf->data() + 64 + 16, &textureScale, 8);
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index ec835fe3bd..08d1c726ab 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -214,9 +214,7 @@ QSGRenderLoop *QSGRenderLoop::instance()
{
if (!s_instance) {
- // For compatibility with 5.3 and earlier's QSG_INFO environment variables
- if (qEnvironmentVariableIsSet("QSG_INFO"))
- const_cast<QLoggingCategory &>(QSG_LOG_INFO()).setEnabled(QtDebugMsg, true);
+ QSGRhiSupport::checkEnvQSgInfo();
s_instance = QSGContext::createWindowManager();
#ifdef ENABLE_DEFAULT_BACKEND
@@ -244,25 +242,28 @@ QSGRenderLoop *QSGRenderLoop::instance()
}
if (rhiSupport->isRhiEnabled()) {
- // no 'windows' because that's not yet ported to the rhi
- if (loopType == WindowsRenderLoop)
- loopType = BasicRenderLoop;
-
switch (rhiSupport->rhiBackend()) {
- case QRhi::D3D11:
- // D3D11 is forced to 'basic' always for now. The threaded loop's model may
- // not be suitable for DXGI due to the possibility of having the main
- // thread blocked while issuing a Present. To be investigated.
+ case QRhi::Null:
loopType = BasicRenderLoop;
break;
- case QRhi::Null:
- loopType = BasicRenderLoop;
+ case QRhi::D3D11:
+ // The threaded loop's model may not be suitable for DXGI
+ // due to the possibility of having the main thread (with
+ // the Windows message pump) blocked while issuing a
+ // Present on the render thread. However, according to the
+ // docs this can be a problem for fullscreen swapchains
+ // only. So leave threaded enabled by default for now and
+ // revisit later if there are problems.
break;
default:
break;
}
+
+ // no 'windows' because that's not yet ported to the rhi
+ if (loopType == WindowsRenderLoop)
+ loopType = BasicRenderLoop;
}
// The environment variables can always override. This is good
@@ -383,20 +384,23 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window)
QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
bool current = false;
- if (gl) {
- QSurface *surface = window;
- // There may be no platform window if the window got closed.
- if (!window->handle())
- surface = offscreenSurface;
+ if (gl || rhi) {
if (rhi) {
+ // Direct OpenGL calls in user code need a current context, like
+ // when rendering; ensure this (no-op when not running on GL).
+ // Also works when there is no handle() anymore.
rhi->makeThreadLocalNativeContextCurrent();
current = true;
} else {
+ QSurface *surface = window;
+ // There may be no platform window if the window got closed.
+ if (!window->handle())
+ surface = offscreenSurface;
current = gl->makeCurrent(surface);
}
+ if (Q_UNLIKELY(!current))
+ qCDebug(QSG_LOG_RENDERLOOP, "cleanup without an OpenGL context");
}
- if (Q_UNLIKELY(!current))
- qCDebug(QSG_LOG_RENDERLOOP, "cleanup without an OpenGL context");
#if QT_CONFIG(quick_shadereffect)
QSGRhiShaderEffectNode::cleanupMaterialTypeCache();
diff --git a/src/quick/scenegraph/qsgrhisupport.cpp b/src/quick/scenegraph/qsgrhisupport.cpp
index 8bae24dc76..a92b6b0c84 100644
--- a/src/quick/scenegraph/qsgrhisupport.cpp
+++ b/src/quick/scenegraph/qsgrhisupport.cpp
@@ -109,6 +109,12 @@ void QSGRhiSupport::applySettings()
{
m_set = true;
+ // This is also done when creating the renderloop but we may be before that
+ // in case we get here due to a setScenegraphBackend() -> configure() early
+ // on in main(). Avoid losing info logs since troubleshooting gets
+ // confusing otherwise.
+ QSGRhiSupport::checkEnvQSgInfo();
+
if (m_requested.valid) {
// explicit rhi backend request from C++ (e.g. via QQuickWindow)
m_enableRhi = m_requested.rhi;
@@ -203,6 +209,13 @@ QSGRhiSupport *QSGRhiSupport::staticInst()
return &inst;
}
+void QSGRhiSupport::checkEnvQSgInfo()
+{
+ // For compatibility with 5.3 and earlier's QSG_INFO environment variables
+ if (qEnvironmentVariableIsSet("QSG_INFO"))
+ const_cast<QLoggingCategory &>(QSG_LOG_INFO()).setEnabled(QtDebugMsg, true);
+}
+
void QSGRhiSupport::configure(QSGRendererInterface::GraphicsApi api)
{
Q_ASSERT(QSGRendererInterface::isApiRhiBased(api));
diff --git a/src/quick/scenegraph/qsgrhisupport_p.h b/src/quick/scenegraph/qsgrhisupport_p.h
index 48ad2f05ae..f2d5837bba 100644
--- a/src/quick/scenegraph/qsgrhisupport_p.h
+++ b/src/quick/scenegraph/qsgrhisupport_p.h
@@ -86,6 +86,7 @@ QT_BEGIN_NAMESPACE
class QSGDefaultRenderContext;
class QVulkanInstance;
+class QOffscreenSurface;
// Opting in/out of QRhi and choosing the default/requested backend is managed
// by this singleton. This is because this information may be needed before
@@ -125,6 +126,8 @@ public:
QImage grabAndBlockInCurrentFrame(QRhi *rhi, QRhiSwapChain *swapchain);
+ static void checkEnvQSgInfo();
+
private:
QSGRhiSupport();
void applySettings();
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index d1258cf903..9e34a2b201 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -147,10 +147,6 @@ const QEvent::Type WM_Obscure = QEvent::Type(QEvent::User + 1);
// (updatePaintNode())
const QEvent::Type WM_RequestSync = QEvent::Type(QEvent::User + 2);
-// Passed by the RT to itself to trigger another render pass. This is
-// typically a result of QQuickWindow::update().
-const QEvent::Type WM_RequestRepaint = QEvent::Type(QEvent::User + 3);
-
// Passed by the RL to the RT to free up maybe release SG and GL contexts
// if no windows are rendering.
const QEvent::Type WM_TryRelease = QEvent::Type(QEvent::User + 4);
@@ -510,13 +506,6 @@ bool QSGRenderThread::event(QEvent *e)
return true;
}
- case WM_RequestRepaint:
- qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "WM_RequestPaint");
- // When GUI posts this event, it is followed by a polishAndSync, so we mustn't
- // exit the event loop yet.
- pendingUpdate |= RepaintRequest;
- break;
-
default:
break;
}
diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri
index ee9ea0f5ed..c345f3b16d 100644
--- a/src/quick/scenegraph/scenegraph.pri
+++ b/src/quick/scenegraph/scenegraph.pri
@@ -53,6 +53,7 @@ HEADERS += \
$$PWD/util/qsgengine.h \
$$PWD/util/qsgengine_p.h \
$$PWD/util/qsgplaintexture_p.h \
+ $$PWD/util/qsgrhinativetextureimporter_p.h \
$$PWD/util/qsgsimplerectnode.h \
$$PWD/util/qsgsimpletexturenode.h \
$$PWD/util/qsgtextureprovider.h \
@@ -69,6 +70,7 @@ SOURCES += \
$$PWD/util/qsgareaallocator.cpp \
$$PWD/util/qsgengine.cpp \
$$PWD/util/qsgplaintexture.cpp \
+ $$PWD/util/qsgrhinativetextureimporter.cpp \
$$PWD/util/qsgsimplerectnode.cpp \
$$PWD/util/qsgsimpletexturenode.cpp \
$$PWD/util/qsgtextureprovider.cpp \
diff --git a/src/quick/scenegraph/shaders_ng/visualization.vert b/src/quick/scenegraph/shaders_ng/visualization.vert
index c29492417a..e2447948c2 100644
--- a/src/quick/scenegraph/shaders_ng/visualization.vert
+++ b/src/quick/scenegraph/shaders_ng/visualization.vert
@@ -11,7 +11,7 @@ layout(std140, binding = 0) uniform buf {
int projection;
} ubuf;
-out gl_PerVertex { vec4 gl_Position; };
+out gl_PerVertex { vec4 gl_Position; float gl_PointSize; };
void main()
{
@@ -25,4 +25,6 @@ void main()
}
pos = v.xy * 1.37;
+
+ gl_PointSize = 1.0;
}
diff --git a/src/quick/scenegraph/shaders_ng/visualization.vert.qsb b/src/quick/scenegraph/shaders_ng/visualization.vert.qsb
index bd89847dd3..7ba27cb4b5 100644
--- a/src/quick/scenegraph/shaders_ng/visualization.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/visualization.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp b/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp
index a850f72053..1154c06d7c 100644
--- a/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp
+++ b/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp
@@ -183,7 +183,9 @@ void QSGDefaultDepthStencilBuffer::free()
QSGDepthStencilBufferManager::~QSGDepthStencilBufferManager()
{
for (Hash::const_iterator it = m_buffers.constBegin(), cend = m_buffers.constEnd(); it != cend; ++it) {
- QSGDepthStencilBuffer *buffer = it.value().toStrongRef().data();
+ QSharedPointer<QSGDepthStencilBuffer> buffer = it.value().toStrongRef();
+ Q_ASSERT_X(buffer, "~QSGDepthStencilBufferManager",
+ "~QSGDepthStencilBuffer is supposed to unregister from the manager");
buffer->free();
buffer->m_manager = nullptr;
}
diff --git a/src/quick/scenegraph/util/qsgengine.cpp b/src/quick/scenegraph/util/qsgengine.cpp
index c05005c467..4880d98871 100644
--- a/src/quick/scenegraph/util/qsgengine.cpp
+++ b/src/quick/scenegraph/util/qsgengine.cpp
@@ -69,6 +69,10 @@ QT_BEGIN_NAMESPACE
Most of the time you will instead want to subclass QQuickItem and insert
your QSGNode in a normal QtQuick scene by overriding QQuickItem::updatePaintNode().
+ \warning This class is only suitable when working directly with OpenGL. It
+ is not compatible with the \l{Scene Graph Adaptations}{RHI-based rendering
+ path}.
+
\sa QSGAbstractRenderer
*/
diff --git a/src/quick/scenegraph/util/qsgengine.h b/src/quick/scenegraph/util/qsgengine.h
index e48b7784ae..c5a59b47e7 100644
--- a/src/quick/scenegraph/util/qsgengine.h
+++ b/src/quick/scenegraph/util/qsgengine.h
@@ -54,6 +54,8 @@ class QSGRectangleNode;
class QSGImageNode;
class QSGNinePatchNode;
+// ### Qt 6: Remove or redesign.
+
class Q_QUICK_EXPORT QSGEngine : public QObject
{
Q_OBJECT
diff --git a/src/quick/scenegraph/util/qsgplaintexture.cpp b/src/quick/scenegraph/util/qsgplaintexture.cpp
index 4c2b452b45..fdebe03494 100644
--- a/src/quick/scenegraph/util/qsgplaintexture.cpp
+++ b/src/quick/scenegraph/util/qsgplaintexture.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qsgplaintexture_p.h"
+#include "qsgrhinativetextureimporter_p.h"
#include <QtQuick/private/qsgcontext_p.h>
#include <qmath.h>
#include <private/qquickprofiler_p.h>
@@ -274,6 +275,24 @@ void QSGPlainTexture::setTexture(QRhiTexture *texture) // RHI only
m_mipmaps_generated = false;
}
+void QSGPlainTexture::setTextureFromNativeObject(QRhi *rhi, QQuickWindow::NativeObjectType type,
+ const void *nativeObjectPtr, int nativeLayout,
+ const QSize &size, bool mipmap)
+{
+ Q_UNUSED(type);
+
+ QRhiTexture::Flags flags = 0;
+ if (mipmap)
+ flags |= QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips;
+
+ QRhiTexture *t = rhi->newTexture(QRhiTexture::RGBA8, size, 1, flags);
+
+ // ownership of the native object is never taken
+ QSGRhiNativeTextureImporter::buildWrapper(rhi, t, nativeObjectPtr, nativeLayout);
+
+ setTexture(t);
+}
+
int QSGPlainTexturePrivate::comparisonKey() const
{
Q_Q(const QSGPlainTexture);
@@ -378,6 +397,19 @@ void QSGPlainTexturePrivate::updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch
q->m_texture_size = tmp.size();
}
+ if ((q->mipmapFiltering() != QSGTexture::None
+ || q->horizontalWrapMode() != QSGTexture::ClampToEdge
+ || q->verticalWrapMode() != QSGTexture::ClampToEdge)
+ && !rhi->isFeatureSupported(QRhi::NPOTTextureRepeat))
+ {
+ const int w = qNextPowerOfTwo(tmp.width() - 1);
+ const int h = qNextPowerOfTwo(tmp.height() - 1);
+ if (tmp.width() != w || tmp.height() != h) {
+ tmp = tmp.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ q->m_texture_size = tmp.size();
+ }
+ }
+
bool needsRebuild = q->m_texture && q->m_texture->pixelSize() != q->m_texture_size;
if (mipmappingChanged) {
diff --git a/src/quick/scenegraph/util/qsgplaintexture_p.h b/src/quick/scenegraph/util/qsgplaintexture_p.h
index 69c0153f9a..1eb0b59d2e 100644
--- a/src/quick/scenegraph/util/qsgplaintexture_p.h
+++ b/src/quick/scenegraph/util/qsgplaintexture_p.h
@@ -53,6 +53,7 @@
#include <QtQuick/private/qtquickglobal_p.h>
#include <QtQuick/private/qsgtexture_p.h>
+#include <QtQuick/qquickwindow.h>
QT_BEGIN_NAMESPACE
@@ -85,6 +86,9 @@ public:
void bind() override;
void setTexture(QRhiTexture *texture);
+ void setTextureFromNativeObject(QRhi *rhi, QQuickWindow::NativeObjectType type,
+ const void *nativeObjectPtr, int nativeLayout,
+ const QSize &size, bool mipmap);
static QSGPlainTexture *fromImage(const QImage &image) {
QSGPlainTexture *t = new QSGPlainTexture();
diff --git a/src/quick/scenegraph/util/qsgrhinativetextureimporter.cpp b/src/quick/scenegraph/util/qsgrhinativetextureimporter.cpp
new file mode 100644
index 0000000000..7a7c19f587
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgrhinativetextureimporter.cpp
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgrhinativetextureimporter_p.h"
+#include <private/qsgrhisupport_p.h> // to get all the relevant qrhi headers
+
+QT_BEGIN_NAMESPACE
+
+void QSGRhiNativeTextureImporter::buildWrapper(QRhi *rhi, QRhiTexture *t,
+ const void *nativeObjectPtr, int nativeLayout)
+{
+#if !QT_CONFIG(vulkan)
+ Q_UNUSED(nativeLayout);
+#endif
+#if !QT_CONFIG(opengl) && !QT_CONFIG(vulkan) && !defined(Q_OS_WIN) && !defined(Q_OS_DARWIN)
+ Q_UNUSED(nativeObjectPtr);
+#endif
+
+ switch (rhi->backend()) {
+ case QRhi::OpenGLES2:
+ {
+#if QT_CONFIG(opengl)
+ QRhiGles2TextureNativeHandles h;
+ h.texture = *reinterpret_cast<const uint *>(nativeObjectPtr);
+ t->buildFrom(&h);
+#endif
+ }
+ break;
+ case QRhi::Vulkan:
+ {
+#if QT_CONFIG(vulkan)
+ QRhiVulkanTextureNativeHandles h;
+ h.image = *reinterpret_cast<const VkImage *>(nativeObjectPtr);
+ h.layout = VkImageLayout(nativeLayout);
+ t->buildFrom(&h);
+#endif
+ }
+ break;
+ case QRhi::D3D11:
+ {
+#ifdef Q_OS_WIN
+ QRhiD3D11TextureNativeHandles h;
+ h.texture = *reinterpret_cast<void * const *>(nativeObjectPtr);
+ t->buildFrom(&h);
+#endif
+ }
+ break;
+ case QRhi::Metal:
+ {
+#ifdef Q_OS_DARWIN
+ QRhiMetalTextureNativeHandles h;
+ h.texture = *reinterpret_cast<void * const *>(nativeObjectPtr);
+ t->buildFrom(&h);
+#endif
+ }
+ break;
+ case QRhi::Null:
+ t->build();
+ break;
+ default:
+ qWarning("QSGRhiNativeTextureImporter: encountered an unsupported QRhi backend (%d)",
+ int(rhi->backend()));
+ t->build();
+ break;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgrhinativetextureimporter_p.h b/src/quick/scenegraph/util/qsgrhinativetextureimporter_p.h
new file mode 100644
index 0000000000..e811109a94
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgrhinativetextureimporter_p.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGRHINATIVETEXTUREIMPORTER_P_H
+#define QSGRHINATIVETEXTUREIMPORTER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuick/private/qtquickglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRhi;
+class QRhiTexture;
+
+class QSGRhiNativeTextureImporter
+{
+public:
+ static void buildWrapper(QRhi *rhi, QRhiTexture *t,
+ const void *nativeObjectPtr, int nativeLayout);
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGRHINATIVETEXTUREIMPORTER_P_H
diff --git a/src/quick/scenegraph/util/qsgtexturematerial.cpp b/src/quick/scenegraph/util/qsgtexturematerial.cpp
index a154ae269a..df4e5cfde2 100644
--- a/src/quick/scenegraph/util/qsgtexturematerial.cpp
+++ b/src/quick/scenegraph/util/qsgtexturematerial.cpp
@@ -164,6 +164,7 @@ void QSGOpaqueTextureMaterialRhiShader::updateSampledImage(const RenderState &st
if (isNpot) {
t->setHorizontalWrapMode(QSGTexture::ClampToEdge);
t->setVerticalWrapMode(QSGTexture::ClampToEdge);
+ t->setMipmapFiltering(QSGTexture::None);
}
}
diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp
index d246ee7910..61319c388c 100644
--- a/src/quick/util/qquickpath.cpp
+++ b/src/quick/util/qquickpath.cpp
@@ -2397,32 +2397,42 @@ void QQuickPathPercent::setValue(qreal value)
\qmlproperty list<point> QtQuick::PathPolyline::path
This property defines the vertices of the polyline.
+
+ It can be a JS array of points constructed with \c Qt.point(),
+ a QList or QVector of QPointF, or QPolygonF.
+ If you are binding this to a custom property in some C++ object,
+ QPolygonF is the most appropriate type to use.
*/
QQuickPathPolyline::QQuickPathPolyline(QObject *parent) : QQuickCurve(parent)
{
}
-QVariantList QQuickPathPolyline::path() const
+QVariant QQuickPathPolyline::path() const
{
- QVariantList res;
- for (int i = 0; i < m_path.length(); ++i) {
- const QPointF &c = m_path.at(i);
- res.append(QVariant::fromValue(c));
- }
-
- return res;
+ return QVariant::fromValue(m_path);
}
-void QQuickPathPolyline::setPath(const QVariantList &path)
+void QQuickPathPolyline::setPath(const QVariant &path)
{
- QVector<QPointF> pathList;
- for (int i = 0; i < path.length(); ++i) {
- const QPointF c = path.at(i).toPointF();
- pathList.append(c);
+ if (path.type() == QVariant::PolygonF) {
+ setPath(path.value<QPolygonF>());
+ } else if (path.canConvert<QVector<QPointF>>()) {
+ setPath(path.value<QVector<QPointF>>());
+ } else if (path.canConvert<QVariantList>()) {
+ // This handles cases other than QPolygonF or QVector<QPointF>, such as
+ // QList<QPointF>, QVector<QPoint>, QVariantList of QPointF, QVariantList of QPoint.
+ QVector<QPointF> pathList;
+ QVariantList vl = path.value<QVariantList>();
+ // If path is a QJSValue, e.g. coming from a JS array of Qt.point() in QML,
+ // then path.value<QVariantList>() is inefficient.
+ // TODO We should be able to iterate over path.value<QSequentialIterable>() eventually
+ for (const QVariant &v : vl)
+ pathList.append(v.toPointF());
+ setPath(pathList);
+ } else {
+ qWarning() << "PathPolyline: path of type" << path.type() << "not supported";
}
-
- setPath(pathList);
}
void QQuickPathPolyline::setPath(const QVector<QPointF> &path)
@@ -2522,48 +2532,60 @@ void QQuickPathPolyline::addToPath(QPainterPath &path, const QQuickPathData &/*d
\qmlproperty list<list<point>> QtQuick::PathMultiline::paths
This property defines the vertices of the polylines.
+
+ It can be a JS array of JS arrays of points constructed with \c Qt.point(),
+ a QList or QVector of QPolygonF, or QVector<QVector<QPointF>>.
+ If you are binding this to a custom property in some C++ object,
+ QVector<QPolygonF> or QVector<QVector<QPointF>> is the most
+ appropriate type to use.
*/
QQuickPathMultiline::QQuickPathMultiline(QObject *parent) : QQuickCurve(parent)
{
}
-QVariantList QQuickPathMultiline::paths() const
-{
- QVariantList res;
- for (int j = 0; j < m_paths.length(); ++j) {
- const QVector<QPointF> &path = m_paths.at(j);
- QVariantList p;
- for (int i = 0; i < path.length(); ++i) {
- const QPointF &c = path.at(i);
- p.append(QVariant::fromValue(c));
- }
- res.append(p);
- }
- return res;
-}
-
-void QQuickPathMultiline::setPaths(const QVariantList &paths)
-{
- QVector<QVector<QPointF>> pathsList;
- for (int j = 0; j < paths.length(); ++j) {
- if (paths.at(j).type() != QVariant::List)
- qWarning() << "QQuickPathMultiLine::setPaths: elements in argument not of type List";
- QVariantList path = paths.at(j).toList();
- QVector<QPointF> l;
- for (int i = 0; i < path.length(); ++i) {
- const QVariant &element = path.at(i);
- const QVariant::Type elementType = element.type();
- if (elementType == QVariant::PointF || elementType == QVariant::Point) {
- const QPointF c = element.toPointF();
- l.append(c);
+QVariant QQuickPathMultiline::paths() const
+{
+ return QVariant::fromValue(m_paths);
+}
+
+void QQuickPathMultiline::setPaths(const QVariant &paths)
+{
+ if (paths.canConvert<QVector<QPolygonF>>()) {
+ const QVector<QPolygonF> pathPolygons = paths.value<QVector<QPolygonF>>();
+ QVector<QVector<QPointF>> pathVectors;
+ for (const QPolygonF &p : pathPolygons)
+ pathVectors << p;
+ setPaths(pathVectors);
+ } else if (paths.canConvert<QVector<QVector<QPointF>>>()) {
+ setPaths(paths.value<QVector<QVector<QPointF>>>());
+ } else if (paths.canConvert<QVariantList>()) {
+ // This handles cases other than QVector<QPolygonF> or QVector<QVector<QPointF>>, such as
+ // QList<QVector<QPointF>>, QList<QList<QPointF>>, QVariantList of QVector<QPointF>,
+ // QVariantList of QVariantList of QPointF, QVector<QList<QPoint>> etc.
+ QVector<QVector<QPointF>> pathsList;
+ QVariantList vll = paths.value<QVariantList>();
+ for (const QVariant &v : vll) {
+ // If we bind a QVector<QPolygonF> property directly, rather than via QVariant,
+ // it will come through as QJSValue that can be converted to QVariantList of QPolygonF.
+ if (v.canConvert<QPolygonF>()) {
+ pathsList.append(v.value<QPolygonF>());
+ } else {
+ QVariantList vl = v.value<QVariantList>();
+ QVector<QPointF> l;
+ for (const QVariant &point : vl) {
+ if (point.canConvert<QPointF>())
+ l.append(point.toPointF());
+ }
+ if (l.size() >= 2)
+ pathsList.append(l);
}
}
- if (l.size() >= 2)
- pathsList.append(l);
+ setPaths(pathsList);
+ } else {
+ qWarning() << "PathMultiline: paths of type" << paths.type() << "not supported";
+ setPaths(QVector<QVector<QPointF>>());
}
-
- setPaths(pathsList);
}
void QQuickPathMultiline::setPaths(const QVector<QVector<QPointF>> &paths)
diff --git a/src/quick/util/qquickpath_p.h b/src/quick/util/qquickpath_p.h
index aa3425ff6c..5987ae8f35 100644
--- a/src/quick/util/qquickpath_p.h
+++ b/src/quick/util/qquickpath_p.h
@@ -290,7 +290,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPathArc : public QQuickCurve
Q_PROPERTY(qreal radiusY READ radiusY WRITE setRadiusY NOTIFY radiusYChanged)
Q_PROPERTY(bool useLargeArc READ useLargeArc WRITE setUseLargeArc NOTIFY useLargeArcChanged)
Q_PROPERTY(ArcDirection direction READ direction WRITE setDirection NOTIFY directionChanged)
- Q_PROPERTY(qreal xAxisRotation READ xAxisRotation WRITE setXAxisRotation NOTIFY xAxisRotationChanged REVISION 2)
+ Q_PROPERTY(qreal xAxisRotation READ xAxisRotation WRITE setXAxisRotation NOTIFY xAxisRotationChanged REVISION 9)
public:
QQuickPathArc(QObject *parent=nullptr)
@@ -321,7 +321,7 @@ Q_SIGNALS:
void radiusYChanged();
void useLargeArcChanged();
void directionChanged();
- Q_REVISION(2) void xAxisRotationChanged();
+ Q_REVISION(9) void xAxisRotationChanged();
private:
qreal _radiusX = 0;
@@ -428,12 +428,12 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPathPolyline : public QQuickCurve
{
Q_OBJECT
Q_PROPERTY(QPointF start READ start NOTIFY startChanged)
- Q_PROPERTY(QVariantList path READ path WRITE setPath NOTIFY pathChanged)
+ Q_PROPERTY(QVariant path READ path WRITE setPath NOTIFY pathChanged)
public:
QQuickPathPolyline(QObject *parent=nullptr);
- QVariantList path() const;
- void setPath(const QVariantList &path);
+ QVariant path() const;
+ void setPath(const QVariant &path);
void setPath(const QVector<QPointF> &path);
QPointF start() const;
void addToPath(QPainterPath &path, const QQuickPathData &data) override;
@@ -450,12 +450,12 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPathMultiline : public QQuickCurve
{
Q_OBJECT
Q_PROPERTY(QPointF start READ start NOTIFY startChanged)
- Q_PROPERTY(QVariantList paths READ paths WRITE setPaths NOTIFY pathsChanged)
+ Q_PROPERTY(QVariant paths READ paths WRITE setPaths NOTIFY pathsChanged)
public:
QQuickPathMultiline(QObject *parent=nullptr);
- QVariantList paths() const;
- void setPaths(const QVariantList &paths);
+ QVariant paths() const;
+ void setPaths(const QVariant &paths);
void setPaths(const QVector<QVector<QPointF>> &paths);
QPointF start() const;
void addToPath(QPainterPath &path, const QQuickPathData &) override;
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index 78a4e5b998..56ad8ebf0b 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -241,7 +241,7 @@ class QQuickPixmapData
{
public:
QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, const QSize &s, const QQuickImageProviderOptions &po, const QString &e)
- : refCount(1), inCache(false), pixmapStatus(QQuickPixmap::Error),
+ : refCount(1), frameCount(1), frame(0), inCache(false), pixmapStatus(QQuickPixmap::Error),
url(u), errorString(e), requestSize(s),
providerOptions(po), appliedTransform(QQuickImageProviderOptions::UsePluginDefaultTransform),
textureFactory(nullptr), reply(nullptr), prevUnreferenced(nullptr),
@@ -250,8 +250,8 @@ public:
declarativePixmaps.insert(pixmap);
}
- QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, const QSize &r, const QQuickImageProviderOptions &po, QQuickImageProviderOptions::AutoTransform aTransform)
- : refCount(1), inCache(false), pixmapStatus(QQuickPixmap::Loading),
+ QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, const QSize &r, const QQuickImageProviderOptions &po, QQuickImageProviderOptions::AutoTransform aTransform, int frame=0, int frameCount=1)
+ : refCount(1), frameCount(frameCount), frame(frame), inCache(false), pixmapStatus(QQuickPixmap::Loading),
url(u), requestSize(r),
providerOptions(po), appliedTransform(aTransform),
textureFactory(nullptr), reply(nullptr), prevUnreferenced(nullptr), prevUnreferencedPtr(nullptr),
@@ -261,8 +261,8 @@ public:
}
QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, QQuickTextureFactory *texture,
- const QSize &s, const QSize &r, const QQuickImageProviderOptions &po, QQuickImageProviderOptions::AutoTransform aTransform)
- : refCount(1), inCache(false), pixmapStatus(QQuickPixmap::Ready),
+ const QSize &s, const QSize &r, const QQuickImageProviderOptions &po, QQuickImageProviderOptions::AutoTransform aTransform, int frame=0, int frameCount=1)
+ : refCount(1), frameCount(frameCount), frame(frame), inCache(false), pixmapStatus(QQuickPixmap::Ready),
url(u), implicitSize(s), requestSize(r),
providerOptions(po), appliedTransform(aTransform),
textureFactory(texture), reply(nullptr), prevUnreferenced(nullptr),
@@ -272,7 +272,7 @@ public:
}
QQuickPixmapData(QQuickPixmap *pixmap, QQuickTextureFactory *texture)
- : refCount(1), inCache(false), pixmapStatus(QQuickPixmap::Ready),
+ : refCount(1), frameCount(1), frame(0), inCache(false), pixmapStatus(QQuickPixmap::Ready),
appliedTransform(QQuickImageProviderOptions::UsePluginDefaultTransform),
textureFactory(texture), reply(nullptr), prevUnreferenced(nullptr),
prevUnreferencedPtr(nullptr), nextUnreferenced(nullptr)
@@ -299,6 +299,8 @@ public:
void removeFromCache();
uint refCount;
+ int frameCount;
+ int frame;
bool inCache:1;
@@ -396,9 +398,9 @@ static void maybeRemoveAlpha(QImage *image)
}
}
-static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *errorString, QSize *impsize,
+static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *errorString, QSize *impsize, int *frameCount,
const QSize &requestSize, const QQuickImageProviderOptions &providerOptions,
- QQuickImageProviderOptions::AutoTransform *appliedTransform = nullptr)
+ QQuickImageProviderOptions::AutoTransform *appliedTransform = nullptr, int frame = 0)
{
QImageReader imgio(dev);
if (providerOptions.autoTransform() != QQuickImageProviderOptions::UsePluginDefaultTransform)
@@ -406,6 +408,12 @@ static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *e
else if (appliedTransform)
*appliedTransform = imgio.autoTransform() ? QQuickImageProviderOptions::ApplyTransform : QQuickImageProviderOptions::DoNotApplyTransform;
+ if (frame < imgio.imageCount())
+ imgio.jumpToImage(frame);
+
+ if (frameCount)
+ *frameCount = imgio.imageCount();
+
QSize scSize = QQuickImageProviderWithOptions::loadSize(imgio.size(), requestSize, imgio.format(), providerOptions);
if (scSize.isValid())
imgio.setScaledSize(scSize);
@@ -558,9 +566,12 @@ void QQuickPixmapReader::networkRequestDone(QNetworkReply *reply)
QByteArray all = reply->readAll();
QBuffer buff(&all);
buff.open(QIODevice::ReadOnly);
- if (!readImage(reply->url(), &buff, &image, &errorString, &readSize, job->requestSize, job->providerOptions))
+ int frameCount;
+ if (!readImage(reply->url(), &buff, &image, &errorString, &readSize, &frameCount, job->requestSize, job->providerOptions, nullptr, job->data->frame))
error = QQuickPixmapReply::Decoding;
- }
+ else
+ job->data->frameCount = frameCount;
+ }
// send completion event to the QQuickPixmapReply
mutex.lock();
if (!cancelled.contains(job))
@@ -870,10 +881,13 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
mutex.unlock();
return;
} else {
- if (!readImage(url, &f, &image, &errorStr, &readSize, runningJob->requestSize, runningJob->providerOptions)) {
+ int frameCount;
+ if (!readImage(url, &f, &image, &errorStr, &readSize, &frameCount, runningJob->requestSize, runningJob->providerOptions, nullptr, runningJob->data->frame)) {
errorCode = QQuickPixmapReply::Loading;
if (f.fileName() != localFile)
errorStr += QString::fromLatin1(" (%1)").arg(f.fileName());
+ } else if (runningJob->data) {
+ runningJob->data->frameCount = frameCount;
}
}
} else {
@@ -982,17 +996,18 @@ class QQuickPixmapKey
public:
const QUrl *url;
const QSize *size;
+ int frame;
QQuickImageProviderOptions options;
};
inline bool operator==(const QQuickPixmapKey &lhs, const QQuickPixmapKey &rhs)
{
- return *lhs.size == *rhs.size && *lhs.url == *rhs.url && lhs.options == rhs.options;
+ return *lhs.size == *rhs.size && *lhs.url == *rhs.url && lhs.options == rhs.options && lhs.frame == rhs.frame;
}
inline uint qHash(const QQuickPixmapKey &key)
{
- return qHash(*key.url) ^ (key.size->width()*7) ^ (key.size->height()*17) ^ (key.options.autoTransform() * 0x5c5c5c5c);
+ return qHash(*key.url) ^ (key.size->width()*7) ^ (key.size->height()*17) ^ (key.frame*23) ^ (key.options.autoTransform() * 0x5c5c5c5c);
}
class QQuickPixmapStore : public QObject
@@ -1254,7 +1269,7 @@ void QQuickPixmapData::release()
void QQuickPixmapData::addToCache()
{
if (!inCache) {
- QQuickPixmapKey key = { &url, &requestSize, providerOptions };
+ QQuickPixmapKey key = { &url, &requestSize, frame, providerOptions };
pixmapStore()->m_cache.insert(key, this);
inCache = true;
PIXMAP_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapCacheCountChanged>(
@@ -1265,7 +1280,7 @@ void QQuickPixmapData::addToCache()
void QQuickPixmapData::removeFromCache()
{
if (inCache) {
- QQuickPixmapKey key = { &url, &requestSize, providerOptions };
+ QQuickPixmapKey key = { &url, &requestSize, frame, providerOptions };
pixmapStore()->m_cache.remove(key);
inCache = false;
PIXMAP_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapCacheCountChanged>(
@@ -1273,7 +1288,7 @@ void QQuickPixmapData::removeFromCache()
}
}
-static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, QQmlEngine *engine, const QUrl &url, const QSize &requestSize, const QQuickImageProviderOptions &providerOptions, bool *ok)
+static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, QQmlEngine *engine, const QUrl &url, const QSize &requestSize, const QQuickImageProviderOptions &providerOptions, int frame, bool *ok)
{
if (url.scheme() == QLatin1String("image")) {
QSize readSize;
@@ -1296,7 +1311,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
: provider->requestTexture(imageId(url), &readSize, requestSize);
if (texture) {
*ok = true;
- return new QQuickPixmapData(declarativePixmap, url, texture, readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform);
+ return new QQuickPixmapData(declarativePixmap, url, texture, readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform, frame);
}
break;
}
@@ -1307,7 +1322,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
: provider->requestImage(imageId(url), &readSize, requestSize);
if (!image.isNull()) {
*ok = true;
- return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform);
+ return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform, frame);
}
break;
}
@@ -1317,7 +1332,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
: provider->requestPixmap(imageId(url), &readSize, requestSize);
if (!pixmap.isNull()) {
*ok = true;
- return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(pixmap.toImage()), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform);
+ return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(pixmap.toImage()), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform, frame);
}
break;
}
@@ -1347,7 +1362,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
QQuickTextureFactory *factory = texReader.read();
if (factory) {
*ok = true;
- return new QQuickPixmapData(declarativePixmap, url, factory, factory->textureSize(), requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform);
+ return new QQuickPixmapData(declarativePixmap, url, factory, factory->textureSize(), requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform, frame);
} else {
errorString = QQuickPixmap::tr("Error decoding: %1").arg(url.toString());
if (f.fileName() != localFile)
@@ -1356,9 +1371,10 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
} else {
QImage image;
QQuickImageProviderOptions::AutoTransform appliedTransform = providerOptions.autoTransform();
- if (readImage(url, &f, &image, &errorString, &readSize, requestSize, providerOptions, &appliedTransform)) {
+ int frameCount;
+ if (readImage(url, &f, &image, &errorString, &readSize, &frameCount, requestSize, providerOptions, &appliedTransform, frame)) {
*ok = true;
- return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, providerOptions, appliedTransform);
+ return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, providerOptions, appliedTransform, frame, frameCount);
} else if (f.fileName() != localFile) {
errorString += QString::fromLatin1(" (%1)").arg(f.fileName());
}
@@ -1476,6 +1492,13 @@ QQuickImageProviderOptions::AutoTransform QQuickPixmap::autoTransform() const
return QQuickImageProviderOptions::UsePluginDefaultTransform;
}
+int QQuickPixmap::frameCount() const
+{
+ if (d)
+ return d->frameCount;
+ return 0;
+}
+
QQuickTextureFactory *QQuickPixmap::textureFactory() const
{
if (d)
@@ -1554,7 +1577,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques
load(engine, url, requestSize, options, QQuickImageProviderOptions());
}
-void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &requestSize, QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions)
+void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &requestSize, QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions, int frame, int frameCount)
{
if (d) {
d->declarativePixmaps.remove(this);
@@ -1562,7 +1585,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques
d = nullptr;
}
- QQuickPixmapKey key = { &url, &requestSize, providerOptions };
+ QQuickPixmapKey key = { &url, &requestSize, frame, providerOptions };
QQuickPixmapStore *store = pixmapStore();
QHash<QQuickPixmapKey, QQuickPixmapData *>::Iterator iter = store->m_cache.end();
@@ -1574,7 +1597,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques
QSize dummy;
if (requestSize != dummy)
qWarning() << "Ignoring sourceSize request for image url that came from grabToImage. Use the targetSize parameter of the grabToImage() function instead.";
- const QQuickPixmapKey grabberKey = { &url, &dummy, QQuickImageProviderOptions() };
+ const QQuickPixmapKey grabberKey = { &url, &dummy, 0, QQuickImageProviderOptions() };
iter = store->m_cache.find(grabberKey);
} else if (options & QQuickPixmap::Cache)
iter = store->m_cache.find(key);
@@ -1596,7 +1619,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques
if (!(options & QQuickPixmap::Asynchronous)) {
bool ok = false;
PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingStarted>(url));
- d = createPixmapDataSync(this, engine, url, requestSize, providerOptions, &ok);
+ d = createPixmapDataSync(this, engine, url, requestSize, providerOptions, frame, &ok);
if (ok) {
PIXMAP_PROFILE(pixmapLoadingFinished(url, QSize(width(), height())));
if (options & QQuickPixmap::Cache)
@@ -1613,7 +1636,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques
return;
- d = new QQuickPixmapData(this, url, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform);
+ d = new QQuickPixmapData(this, url, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform, frame, frameCount);
if (options & QQuickPixmap::Cache)
d->addToCache();
@@ -1647,9 +1670,9 @@ void QQuickPixmap::clear(QObject *obj)
}
}
-bool QQuickPixmap::isCached(const QUrl &url, const QSize &requestSize, const QQuickImageProviderOptions &options)
+bool QQuickPixmap::isCached(const QUrl &url, const QSize &requestSize, const int frame, const QQuickImageProviderOptions &options)
{
- QQuickPixmapKey key = { &url, &requestSize, options };
+ QQuickPixmapKey key = { &url, &requestSize, frame, options };
QQuickPixmapStore *store = pixmapStore();
return store->m_cache.contains(key);
diff --git a/src/quick/util/qquickpixmapcache_p.h b/src/quick/util/qquickpixmapcache_p.h
index f51b65dd76..c4f4d1a101 100644
--- a/src/quick/util/qquickpixmapcache_p.h
+++ b/src/quick/util/qquickpixmapcache_p.h
@@ -150,6 +150,7 @@ public:
const QSize &implicitSize() const;
const QSize &requestSize() const;
QQuickImageProviderOptions::AutoTransform autoTransform() const;
+ int frameCount() const;
QImage image() const;
void setImage(const QImage &);
void setPixmap(const QQuickPixmap &other);
@@ -164,7 +165,7 @@ public:
void load(QQmlEngine *, const QUrl &, QQuickPixmap::Options options);
void load(QQmlEngine *, const QUrl &, const QSize &);
void load(QQmlEngine *, const QUrl &, const QSize &, QQuickPixmap::Options options);
- void load(QQmlEngine *, const QUrl &, const QSize &, QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions);
+ void load(QQmlEngine *, const QUrl &, const QSize &, QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions, int frame = 0, int frameCount = 1);
void clear();
void clear(QObject *);
@@ -175,7 +176,7 @@ public:
bool connectDownloadProgress(QObject *, int);
static void purgeCache();
- static bool isCached(const QUrl &url, const QSize &requestSize, const QQuickImageProviderOptions &options);
+ static bool isCached(const QUrl &url, const QSize &requestSize, const int frame, const QQuickImageProviderOptions &options);
static const QLatin1String itemGrabberScheme;
diff --git a/src/quick/util/qquickshortcut_p.h b/src/quick/util/qquickshortcut_p.h
index c5d5501cb7..712cca7696 100644
--- a/src/quick/util/qquickshortcut_p.h
+++ b/src/quick/util/qquickshortcut_p.h
@@ -67,8 +67,8 @@ class QQuickShortcut : public QObject, public QQmlParserStatus
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QVariant sequence READ sequence WRITE setSequence NOTIFY sequenceChanged FINAL)
Q_PROPERTY(QVariantList sequences READ sequences WRITE setSequences NOTIFY sequencesChanged FINAL REVISION 9)
- Q_PROPERTY(QString nativeText READ nativeText NOTIFY sequenceChanged FINAL REVISION 1)
- Q_PROPERTY(QString portableText READ portableText NOTIFY sequenceChanged FINAL REVISION 1)
+ Q_PROPERTY(QString nativeText READ nativeText NOTIFY sequenceChanged FINAL REVISION 6)
+ Q_PROPERTY(QString portableText READ portableText NOTIFY sequenceChanged FINAL REVISION 6)
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL)
Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat NOTIFY autoRepeatChanged FINAL)
Q_PROPERTY(Qt::ShortcutContext context READ context WRITE setContext NOTIFY contextChanged FINAL)
diff --git a/src/quick/util/qquicktransition.cpp b/src/quick/util/qquicktransition.cpp
index c8699426f2..b973309212 100644
--- a/src/quick/util/qquicktransition.cpp
+++ b/src/quick/util/qquicktransition.cpp
@@ -82,13 +82,15 @@ QT_BEGIN_NAMESPACE
values can be set to restrict the animations to only be applied when changing
from one particular state to another.
- To define multiple transitions, specify \l Item::transitions as a list:
+ To define multiple Transitions, specify \l Item::transitions as a list:
\snippet qml/transitions-list.qml list of transitions
- If multiple Transitions are specified, only a single (best-matching) Transition will be applied for any particular
- state change. In the example above, when changing to \c state1, the first transition will be used, rather
- than the more generic second transition.
+ If multiple Transitions are specified, only a single (best-matching)
+ Transition will be applied for any particular state change. In the
+ example above, if the Rectangle enters a state other than \c "middleRight"
+ or \c "bottomLeft", the third Transition will be carried out, meaning the
+ icon will be moved to the starting point.
If a state change has a Transition that matches the same property as a
\l Behavior, the Transition animation overrides the \l Behavior for that
@@ -298,10 +300,11 @@ QQuickTransitionInstance *QQuickTransition::prepare(QQuickStateOperation::Action
\snippet qml/transition-from-to-modified.qml modified transition
- The animation would only be applied when changing from the default state to
- the "brighter" state (i.e. when the mouse is pressed, but not on release).
+ The animation would only be applied when changing from the default state
+ to the "brighter" state (i.e. when the mouse is pressed, but not on release).
- Multiple \c to and \c from values can be set by using a comma-separated string.
+ Multiple \c to and \c from values can be set by using a comma-separated
+ string.
\sa reversible
*/
@@ -323,7 +326,8 @@ void QQuickTransition::setFromState(const QString &f)
/*!
\qmlproperty bool QtQuick::Transition::reversible
- This property holds whether the transition should be automatically reversed when the conditions that triggered this transition are reversed.
+ This property holds whether the transition should be automatically
+ reversed when the conditions that triggered this transition are reversed.
The default value is false.
diff --git a/src/quick/util/qquickutilmodule.cpp b/src/quick/util/qquickutilmodule.cpp
index d222a0c0be..93b6599506 100644
--- a/src/quick/util/qquickutilmodule.cpp
+++ b/src/quick/util/qquickutilmodule.cpp
@@ -99,7 +99,7 @@ void QQuickUtilModule::defineModule()
qmlRegisterType<QQuickVector3dAnimation>("QtQuick",2,0,"Vector3dAnimation");
#if QT_CONFIG(validator)
- qmlRegisterType<QValidator>();
+ qmlRegisterAnonymousType<QValidator>("QtQuick", 2);
qmlRegisterType<QQuickIntValidator>("QtQuick",2,0,"IntValidator");
qmlRegisterType<QQuickDoubleValidator>("QtQuick",2,0,"DoubleValidator");
qmlRegisterType<QRegExpValidator>("QtQuick",2,0,"RegExpValidator");
@@ -117,7 +117,7 @@ void QQuickUtilModule::defineModule()
#if QT_CONFIG(quick_shadereffect) && QT_CONFIG(opengl)
qmlRegisterType<QQuickUniformAnimator>("QtQuick", 2, 2, "UniformAnimator");
#endif
- qmlRegisterType<QQuickStateOperation>();
+ qmlRegisterAnonymousType<QQuickStateOperation>("QtQuick", 2);
qmlRegisterCustomType<QQuickPropertyChanges>("QtQuick",2,0,"PropertyChanges", new QQuickPropertyChangesParser);
@@ -131,7 +131,7 @@ void QQuickUtilModule::defineModule()
#if QT_CONFIG(shortcut)
qmlRegisterType<QQuickShortcut>("QtQuick", 2, 5, "Shortcut");
- qmlRegisterType<QQuickShortcut,1>("QtQuick", 2, 6, "Shortcut");
+ qmlRegisterType<QQuickShortcut,6>("QtQuick", 2, 6, "Shortcut");
qmlRegisterType<QQuickShortcut,9>("QtQuick", 2, 9, "Shortcut");
#endif
diff --git a/src/quickshapes/qquickshape.cpp b/src/quickshapes/qquickshape.cpp
index 04e8de5aa0..c1deb0dced 100644
--- a/src/quickshapes/qquickshape.cpp
+++ b/src/quickshapes/qquickshape.cpp
@@ -201,7 +201,7 @@ void QQuickShapePath::setStrokeColor(const QColor &color)
}
/*!
- \qmlproperty color QtQuick.Shapes::ShapePath::strokeWidth
+ \qmlproperty real QtQuick.Shapes::ShapePath::strokeWidth
This property holds the stroke width.
diff --git a/src/src.pro b/src/src.pro
index b1e0a72c9f..98e1779dc5 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -11,9 +11,10 @@ qtConfig(qml-worker-script): \
SUBDIRS += qmlworkerscript
qtHaveModule(gui):qtConfig(qml-animation) {
- SUBDIRS += \
- quick \
- quickshapes
+ SUBDIRS += quick
+
+ qtConfig(quick-path): \
+ SUBDIRS += quickshapes
qtConfig(testlib): \
SUBDIRS += qmltest
diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt
index f304a99705..bda5d626a9 100644
--- a/tests/auto/cmake/CMakeLists.txt
+++ b/tests/auto/cmake/CMakeLists.txt
@@ -27,3 +27,15 @@ add_test(qtquickcompiler ${CMAKE_CTEST_COMMAND}
--build-options "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}" ${BUILD_OPTIONS_LIST}
--test-command qqc_test
)
+
+add_test(qmlimportscanner ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMAKE_CURRENT_SOURCE_DIR}/qmlimportscanner/"
+ "${CMAKE_CURRENT_BINARY_DIR}/qmlimportscanner"
+ --build-config "${CMAKE_BUILD_TYPE}"
+ --build-generator ${CMAKE_GENERATOR}
+ --build-makeprogram ${CMAKE_MAKE_PROGRAM}
+ --build-project qis_test
+ --build-options "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}" ${BUILD_OPTIONS_LIST}
+ --test-command qis_test
+)
diff --git a/tests/auto/cmake/qmlimportscanner/CMakeLists.txt b/tests/auto/cmake/qmlimportscanner/CMakeLists.txt
new file mode 100644
index 0000000000..354b0f8dfc
--- /dev/null
+++ b/tests/auto/cmake/qmlimportscanner/CMakeLists.txt
@@ -0,0 +1,18 @@
+
+cmake_minimum_required(VERSION 3.1)
+project(qis_test)
+
+find_package(Qt5Qml 5.0.0 REQUIRED)
+find_package(Qt5Gui 5.0.0 REQUIRED)
+find_package(Qt5Test 5.0.0 REQUIRED)
+find_package(Qt5QmlImportScanner REQUIRED)
+
+set(CMAKE_CXXFLAGS "${CMAKE_CXXFLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS}")
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+
+add_executable(qis_test "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
+ "${CMAKE_CURRENT_SOURCE_DIR}/qis_test.qrc")
+target_link_libraries(qis_test PRIVATE Qt5::Gui Qt5::Qml Qt5::Test)
+qt5_import_qml_plugins(qis_test)
diff --git a/tests/auto/cmake/qmlimportscanner/main.cpp b/tests/auto/cmake/qmlimportscanner/main.cpp
new file mode 100644
index 0000000000..370b10e113
--- /dev/null
+++ b/tests/auto/cmake/qmlimportscanner/main.cpp
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore>
+#include <QtQml>
+#include <QtTest>
+
+class tst_QQC : public QObject
+{
+ Q_OBJECT
+private slots:
+ void staticBuildTest();
+};
+
+void tst_QQC::staticBuildTest()
+{
+#ifdef QT_STATIC
+ QQmlEngine engine;
+ QQmlComponent component(&engine, QUrl("qrc:/main.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QCOMPARE(obj->property("success").toInt(), 42);
+#endif
+}
+
+QTEST_MAIN(tst_QQC)
+
+#include "main.moc"
diff --git a/tests/auto/cmake/qmlimportscanner/main.qml b/tests/auto/cmake/qmlimportscanner/main.qml
new file mode 100644
index 0000000000..e0101958ea
--- /dev/null
+++ b/tests/auto/cmake/qmlimportscanner/main.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+import QtQuick 2.0
+QtObject {
+ property int success: 42
+}
diff --git a/tests/auto/cmake/qmlimportscanner/qis_test.qrc b/tests/auto/cmake/qmlimportscanner/qis_test.qrc
new file mode 100644
index 0000000000..1f88fc4e71
--- /dev/null
+++ b/tests/auto/cmake/qmlimportscanner/qis_test.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+<file>./main.qml</file>
+<file alias="main.cpp">./main.cpp</file>
+</qresource>
+</RCC>
diff --git a/tests/auto/qml/bindingdependencyapi/dummy_imports.qml b/tests/auto/qml/bindingdependencyapi/dummy_imports.qml
new file mode 100644
index 0000000000..b9a196e188
--- /dev/null
+++ b/tests/auto/qml/bindingdependencyapi/dummy_imports.qml
@@ -0,0 +1,8 @@
+// This file exists for the sole purpose for qmlimportscanner to find
+// which modules it needs to extract for deployment.
+// Otherwise, it fails to find the imports that are expressed in C++
+// code in tst_parserstress.cpp
+
+import QtQuick 2.0
+
+QtObject { } // This is needed in order to keep importscanner happy
diff --git a/tests/auto/qml/qjsengine/dummy_imports.qml b/tests/auto/qml/qjsengine/dummy_imports.qml
new file mode 100644
index 0000000000..8d86f3583b
--- /dev/null
+++ b/tests/auto/qml/qjsengine/dummy_imports.qml
@@ -0,0 +1,8 @@
+// This file exists for the sole purpose for qmlimportscanner to find
+// which modules it needs to extract for deployment.
+// Otherwise, it fails to find the imports that are expressed in C++
+// code in tst_parserstress.cpp
+
+import QtQml 2.0
+
+QtObject { } // This is needed in order to keep importscanner happy
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index 0ccb8210bc..1c895eb793 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -201,7 +201,9 @@ private slots:
void engineForObject();
void intConversion_QTBUG43309();
+#ifdef QT_DEPRECATED
void toFixed();
+#endif
void argumentEvaluationOrder();
@@ -4323,7 +4325,10 @@ void tst_QJSEngine::engineForObject()
QVERIFY(!qjsEngine(&object));
QJSValue wrapper = engine.newQObject(&object);
QQmlEngine::setObjectOwnership(&object, QQmlEngine::CppOwnership);
+ QVERIFY(qjsEngine(&object));
+#ifdef QT_DEPRECATED
QCOMPARE(qjsEngine(&object), wrapper.engine());
+#endif
}
QVERIFY(!qjsEngine(&object));
}
@@ -4338,6 +4343,7 @@ void tst_QJSEngine::intConversion_QTBUG43309()
QCOMPARE(result.toNumber(), 25.0);
}
+#ifdef QT_DEPRECATED
// QTBUG-44039 and QTBUG-43885:
void tst_QJSEngine::toFixed()
{
@@ -4349,6 +4355,7 @@ void tst_QJSEngine::toFixed()
QVERIFY(result.isString());
QCOMPARE(result.toString(), QStringLiteral("12.1"));
}
+#endif
void tst_QJSEngine::argumentEvaluationOrder()
{
diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
index 4de72ae7a1..37d0ea4dea 100644
--- a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
+++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
@@ -52,7 +52,9 @@ void tst_QJSValue::ctor_invalid()
{
QJSValue v;
QVERIFY(v.isUndefined());
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), (QJSEngine *)nullptr);
+#endif
}
}
@@ -63,7 +65,9 @@ void tst_QJSValue::ctor_undefinedWithEngine()
QJSValue v = eng.toScriptValue(QVariant());
QVERIFY(v.isUndefined());
QCOMPARE(v.isObject(), false);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), &eng);
+#endif
}
}
@@ -75,7 +79,9 @@ void tst_QJSValue::ctor_nullWithEngine()
QVERIFY(!v.isUndefined());
QCOMPARE(v.isNull(), true);
QCOMPARE(v.isObject(), false);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), &eng);
+#endif
}
}
@@ -88,7 +94,9 @@ void tst_QJSValue::ctor_boolWithEngine()
QCOMPARE(v.isBool(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toBool(), false);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), &eng);
+#endif
}
}
@@ -101,7 +109,9 @@ void tst_QJSValue::ctor_intWithEngine()
QCOMPARE(v.isNumber(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toNumber(), 1.0);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), &eng);
+#endif
}
}
@@ -118,7 +128,9 @@ void tst_QJSValue::ctor_int()
QCOMPARE(v.isNumber(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toNumber(), 1.0);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), (QJSEngine *)nullptr);
+#endif
}
}
@@ -131,7 +143,9 @@ void tst_QJSValue::ctor_uintWithEngine()
QCOMPARE(v.isNumber(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toNumber(), 1.0);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), &eng);
+#endif
}
}
@@ -148,7 +162,9 @@ void tst_QJSValue::ctor_uint()
QCOMPARE(v.isNumber(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toNumber(), 1.0);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), (QJSEngine *)nullptr);
+#endif
}
}
@@ -161,7 +177,9 @@ void tst_QJSValue::ctor_floatWithEngine()
QCOMPARE(v.isNumber(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toNumber(), 1.0);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), &eng);
+#endif
}
}
@@ -178,7 +196,9 @@ void tst_QJSValue::ctor_float()
QCOMPARE(v.isNumber(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toNumber(), 1.0);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), (QJSEngine *)nullptr);
+#endif
}
}
@@ -191,7 +211,9 @@ void tst_QJSValue::ctor_stringWithEngine()
QCOMPARE(v.isString(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toString(), QLatin1String("ciao"));
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), &eng);
+#endif
}
}
@@ -203,7 +225,9 @@ void tst_QJSValue::ctor_string()
QCOMPARE(v.isString(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toString(), QLatin1String("ciao"));
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), (QJSEngine *)nullptr);
+#endif
}
{
QJSValue v("ciao");
@@ -211,7 +235,9 @@ void tst_QJSValue::ctor_string()
QCOMPARE(v.isString(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toString(), QLatin1String("ciao"));
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), (QJSEngine *)nullptr);
+#endif
}
}
@@ -223,12 +249,16 @@ void tst_QJSValue::ctor_copyAndAssignWithEngine()
QJSValue v = eng.toScriptValue(1.0);
QJSValue v2(v);
QCOMPARE(v2.strictlyEquals(v), true);
+#ifdef QT_DEPRECATED
QCOMPARE(v2.engine(), &eng);
+#endif
QJSValue v3(v);
QCOMPARE(v3.strictlyEquals(v), true);
QCOMPARE(v3.strictlyEquals(v2), true);
+#ifdef QT_DEPRECATED
QCOMPARE(v3.engine(), &eng);
+#endif
QJSValue v4 = eng.toScriptValue(2.0);
QCOMPARE(v4.strictlyEquals(v), false);
@@ -253,7 +283,9 @@ void tst_QJSValue::ctor_undefined()
QJSValue v(QJSValue::UndefinedValue);
QVERIFY(v.isUndefined());
QCOMPARE(v.isObject(), false);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), (QJSEngine *)nullptr);
+#endif
}
void tst_QJSValue::ctor_null()
@@ -262,7 +294,9 @@ void tst_QJSValue::ctor_null()
QVERIFY(!v.isUndefined());
QCOMPARE(v.isNull(), true);
QCOMPARE(v.isObject(), false);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), (QJSEngine *)nullptr);
+#endif
}
void tst_QJSValue::ctor_bool()
@@ -273,7 +307,9 @@ void tst_QJSValue::ctor_bool()
QCOMPARE(v.isBool(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toBool(), false);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), (QJSEngine *)nullptr);
+#endif
}
void tst_QJSValue::ctor_copyAndAssign()
@@ -281,12 +317,16 @@ void tst_QJSValue::ctor_copyAndAssign()
QJSValue v(1.0);
QJSValue v2(v);
QCOMPARE(v2.strictlyEquals(v), true);
+#ifdef QT_DEPRECATED
QCOMPARE(v2.engine(), (QJSEngine *)nullptr);
+#endif
QJSValue v3(v);
QCOMPARE(v3.strictlyEquals(v), true);
QCOMPARE(v3.strictlyEquals(v2), true);
+#ifdef QT_DEPRECATED
QCOMPARE(v3.engine(), (QJSEngine *)nullptr);
+#endif
QJSValue v4(2.0);
QCOMPARE(v4.strictlyEquals(v), false);
@@ -423,7 +463,9 @@ void tst_QJSValue::toString()
QCOMPARE(o.toString(), QStringLiteral("[object Object]"));
o = createUnboundValue(o);
+#ifdef QT_DEPRECATED
QVERIFY(!o.engine());
+#endif
QCOMPARE(o.toString(), QStringLiteral("[object Object]"));
}
@@ -435,7 +477,9 @@ void tst_QJSValue::toString()
QCOMPARE(o.toString(), QStringLiteral("1,2,3"));
o = createUnboundValue(o);
+#ifdef QT_DEPRECATED
QVERIFY(!o.engine());
+#endif
QCOMPARE(o.toString(), QStringLiteral("1,2,3"));
}
@@ -1641,10 +1685,14 @@ void tst_QJSValue::getSetProperty()
QCOMPARE(object.property("baz").toNumber(), num.toNumber());
QJSValue strstr = QJSValue("bar");
+#ifdef QT_DEPRECATED
QCOMPARE(strstr.engine(), (QJSEngine *)nullptr);
+#endif
object.setProperty("foo", strstr);
QCOMPARE(object.property("foo").toString(), strstr.toString());
+#ifdef QT_DEPRECATED
QCOMPARE(strstr.engine(), &eng); // the value has been bound to the engine
+#endif
QJSValue numnum = QJSValue(123.0);
object.setProperty("baz", numnum);
@@ -2536,15 +2584,18 @@ void tst_QJSValue::engineDeleted()
delete eng;
QVERIFY(v1.isUndefined());
- QVERIFY(!v1.engine());
QVERIFY(v2.isUndefined());
- QVERIFY(!v2.engine());
QVERIFY(v3.isUndefined());
- QVERIFY(!v3.engine());
QVERIFY(v4.isUndefined());
- QVERIFY(!v4.engine());
QVERIFY(v5.isString()); // was not bound to engine
+
+#ifdef QT_DEPRECATED
+ QVERIFY(!v1.engine());
+ QVERIFY(!v2.engine());
+ QVERIFY(!v3.engine());
+ QVERIFY(!v4.engine());
QVERIFY(!v5.engine());
+#endif
QVERIFY(v3.property("foo").isUndefined());
}
diff --git a/tests/auto/qml/qmldiskcache/dummy_imports.qml b/tests/auto/qml/qmldiskcache/dummy_imports.qml
new file mode 100644
index 0000000000..b9a196e188
--- /dev/null
+++ b/tests/auto/qml/qmldiskcache/dummy_imports.qml
@@ -0,0 +1,8 @@
+// This file exists for the sole purpose for qmlimportscanner to find
+// which modules it needs to extract for deployment.
+// Otherwise, it fails to find the imports that are expressed in C++
+// code in tst_parserstress.cpp
+
+import QtQuick 2.0
+
+QtObject { } // This is needed in order to keep importscanner happy
diff --git a/tests/auto/qml/qmllint/data/CatchStatement.qml b/tests/auto/qml/qmllint/data/CatchStatement.qml
new file mode 100644
index 0000000000..e0f70fce7e
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/CatchStatement.qml
@@ -0,0 +1,8 @@
+import QtQml 2.12
+
+QtObject {
+ function f() {
+ try {} catch(err) {}
+ console.log(err);
+ }
+}
diff --git a/tests/auto/qml/qmllint/data/catchIdentifierNoWarning.qml b/tests/auto/qml/qmllint/data/catchIdentifierNoWarning.qml
new file mode 100644
index 0000000000..097baa6fcf
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/catchIdentifierNoWarning.qml
@@ -0,0 +1,7 @@
+import QtQml 2.12
+
+QtObject {
+ function f() {
+ try {} catch(err) {console.log(err);}
+ }
+}
diff --git a/tests/auto/qml/qmllint/qmllint.pro b/tests/auto/qml/qmllint/qmllint.pro
index b53a6f6877..95470b4085 100644
--- a/tests/auto/qml/qmllint/qmllint.pro
+++ b/tests/auto/qml/qmllint/qmllint.pro
@@ -1,6 +1,11 @@
-TEMPLATE = app
-TARGET = testqmllint
-INCLUDEPATH += .
+CONFIG += testcase
+TARGET = tst_qmllint
+macos:CONFIG -= app_bundle
+
+SOURCES += tst_qmllint.cpp
+
+include (../../shared/util.pri)
+
+TESTDATA = data/*
-SOURCES += main.cpp
QT += testlib
diff --git a/tests/auto/qml/qmllint/main.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp
index 928575bc82..582f146dca 100644
--- a/tests/auto/qml/qmllint/main.cpp
+++ b/tests/auto/qml/qmllint/tst_qmllint.cpp
@@ -30,23 +30,27 @@
#include <QProcess>
#include <QString>
-class TestQmllint: public QObject
+#include <util.h>
+
+class TestQmllint: public QQmlDataTest
{
Q_OBJECT
private Q_SLOTS:
- void initTestCase();
+ void initTestCase() override;
void test();
void test_data();
void testUnqualified();
void testUnqualified_data();
void testUnqualifiedNoSpuriousParentWarning();
+ void catchIdentifierNoFalsePositive();
private:
QString m_qmllintPath;
};
void TestQmllint::initTestCase()
{
+ QQmlDataTest::initTestCase();
m_qmllintPath = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QLatin1String("/qmllint");
#ifdef Q_OS_WIN
m_qmllintPath += QLatin1String(".exe");
@@ -79,9 +83,8 @@ void TestQmllint::testUnqualified()
QFETCH(QString, warningMessage);
QFETCH(int, warningLine);
QFETCH(int, warningColumn);
- filename.prepend(QStringLiteral("data/"));
QStringList args;
- args << QStringLiteral("-U") << filename << QStringLiteral("-I") << qmlImportDir;
+ args << QStringLiteral("-U") << testFile(filename) << QStringLiteral("-I") << qmlImportDir;
QProcess process;
process.start(m_qmllintPath, args);
@@ -113,15 +116,15 @@ void TestQmllint::testUnqualified_data()
QTest::newRow("SignalHandler2") << QStringLiteral("SignalHandler.qml") << QStringLiteral("onPositionChanged: function(mouse) {...") << 10 << 21;
QTest::newRow("SignalHandlerShort1") << QStringLiteral("SignalHandler.qml") << QStringLiteral("onClicked: (mouse) => {...") << 8 << 29;
QTest::newRow("SignalHandlerShort2") << QStringLiteral("SignalHandler.qml") << QStringLiteral("onPressAndHold: (mouse) => {...") << 12 << 34;
-
+ // access catch identifier outside catch block
+ QTest::newRow("CatchStatement") << QStringLiteral("CatchStatement.qml") << QStringLiteral("err") << 6 << 21;
}
void TestQmllint::testUnqualifiedNoSpuriousParentWarning()
{
auto qmlImportDir = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath);
{
- QString filename = QLatin1String("spuriousParentWarning.qml");
- filename.prepend(QStringLiteral("data/"));
+ QString filename = testFile("spuriousParentWarning.qml");
QStringList args;
args << QStringLiteral("-U") << filename << QStringLiteral("-I") << qmlImportDir;
QProcess process;
@@ -131,8 +134,7 @@ void TestQmllint::testUnqualifiedNoSpuriousParentWarning()
QVERIFY(process.exitCode() == 0);
}
{
- QString filename = QLatin1String("nonSpuriousParentWarning.qml");
- filename.prepend(QStringLiteral("data/"));
+ QString filename = testFile("nonSpuriousParentWarning.qml");
QStringList args;
args << QStringLiteral("-U") << filename << QStringLiteral("-I") << qmlImportDir;
QProcess process;
@@ -143,17 +145,30 @@ void TestQmllint::testUnqualifiedNoSpuriousParentWarning()
}
}
+void TestQmllint::catchIdentifierNoFalsePositive()
+{
+ auto qmlImportDir = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath);
+ QString filename = QLatin1String("catchIdentifierNoWarning.qml");
+ filename.prepend(QStringLiteral("data/"));
+ QStringList args;
+ args << QStringLiteral("-U") << filename << QStringLiteral("-I") << qmlImportDir;
+ QProcess process;
+ process.start(m_qmllintPath, args);
+ QVERIFY(process.waitForFinished());
+ QVERIFY(process.exitStatus() == QProcess::NormalExit);
+ QVERIFY(process.exitCode() == 0);
+}
+
void TestQmllint::test()
{
QFETCH(QString, filename);
QFETCH(bool, isValid);
- filename = QStringLiteral("data/") + filename;
QStringList args;
- args << QStringLiteral("--silent") << filename;
+ args << QStringLiteral("--silent") << testFile(filename);
bool success = QProcess::execute(m_qmllintPath, args) == 0;
QCOMPARE(success, isValid);
}
QTEST_MAIN(TestQmllint)
-#include "main.moc"
+#include "tst_qmllint.moc"
diff --git a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
index 8787a43884..0f5eea8b95 100644
--- a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
+++ b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
@@ -52,6 +52,7 @@ private slots:
void removeObjectsWhenDestroyed();
void loadTranslation_data();
void loadTranslation();
+ void setInitialProperties();
private:
QString buildDir;
@@ -275,6 +276,23 @@ void tst_qqmlapplicationengine::loadTranslation()
QCOMPARE(rootObject->property("translation").toString(), translation);
}
+void tst_qqmlapplicationengine::setInitialProperties()
+{
+ QQmlApplicationEngine test {};
+ {
+ test.setInitialProperties(QVariantMap{{"success", false}});
+ test.load(testFileUrl("basicTest.qml"));
+ QVERIFY(!test.rootObjects().empty());
+ QCOMPARE(test.rootObjects().first()->property("success").toBool(), false);
+ }
+ {
+ test.setInitialProperties({{"success", true}});
+ test.load(testFileUrl("basicTest.qml"));
+ QCOMPARE(test.rootObjects().size(), 2);
+ QCOMPARE(test.rootObjects().at(1)->property("success").toBool(), true);
+ }
+}
+
QTEST_MAIN(tst_qqmlapplicationengine)
#include "tst_qqmlapplicationengine.moc"
diff --git a/tests/auto/qml/qqmlcomponent/data/allJSONTypes.qml b/tests/auto/qml/qqmlcomponent/data/allJSONTypes.qml
new file mode 100644
index 0000000000..0541c9b104
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/allJSONTypes.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.14
+
+Item {
+ property int i
+ property bool b
+ property double d
+ property string s
+ property var nothing
+}
diff --git a/tests/auto/qml/qqmlcomponent/data/variantBasedInitialization.qml b/tests/auto/qml/qqmlcomponent/data/variantBasedInitialization.qml
new file mode 100644
index 0000000000..acf08e94d2
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/variantBasedInitialization.qml
@@ -0,0 +1,21 @@
+import QtQuick 2.14
+
+Item {
+ property int i
+ property bool b
+ property double d
+ property string s
+ property var nothing
+ property url myurl
+ property color c
+ property font myfont
+ property date mydate
+ property point mypoint
+ property size mysize
+ property rect myrect
+ property matrix4x4 matrix
+ property quaternion quat
+ property vector2d vec2
+ property vector3d vec3
+ property vector4d vec4
+}
diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
index 71d3e8fe5f..79ec507388 100644
--- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
+++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
@@ -121,6 +121,7 @@ private slots:
void relativeUrl_data();
void relativeUrl();
void setDataNoEngineNoSegfault();
+ void testSetInitialProperties();
private:
QQmlEngine engine;
@@ -667,6 +668,101 @@ void tst_qqmlcomponent::setDataNoEngineNoSegfault()
QVERIFY(!c);
}
+void tst_qqmlcomponent::testSetInitialProperties()
+{
+ QQmlEngine eng;
+ {
+ // JSON based initialization
+ QQmlComponent comp(&eng);
+ comp.loadUrl(testFileUrl("allJSONTypes.qml"));
+ QScopedPointer<QObject> obj { comp.beginCreate(eng.rootContext()) };
+ QVERIFY(obj);
+ comp.setInitialProperties(obj.get(), QVariantMap {
+ {QLatin1String("i"), 42},
+ {QLatin1String("b"), true},
+ {QLatin1String("d"), 3.1416},
+ {QLatin1String("s"), QLatin1String("hello world")},
+ {QLatin1String("nothing"), QVariant::fromValue(nullptr)}
+ });
+ comp.completeCreate();
+ if (!comp.errors().empty())
+ qDebug() << comp.errorString() << comp.errors();
+ QVERIFY(comp.errors().empty());
+ QCOMPARE(obj->property("i"), 42);
+ QCOMPARE(obj->property("b"), true);
+ QCOMPARE(obj->property("d"), 3.1416);
+ QCOMPARE(obj->property("s"), QLatin1String("hello world"));
+ QCOMPARE(obj->property("nothing"), QVariant::fromValue(nullptr));
+ }
+ {
+ // QVariant
+ QQmlComponent comp(&eng);
+ comp.loadUrl(testFileUrl("variantBasedInitialization.qml"));
+ QScopedPointer<QObject> obj { comp.beginCreate(eng.rootContext()) };
+ QVERIFY(obj);
+ QUrl myurl = comp.url();
+ QFont myfont;
+ QDateTime mydate = QDateTime::currentDateTime();
+ QPoint mypoint {1,2};
+ QSizeF mysize {0.5, 0.3};
+ QMatrix4x4 matrix {};
+ QQuaternion quat {5.0f, 0.3f, 0.2f, 0.1f};
+ QVector2D vec2 {2.0f, 3.1f};
+ QVector3D vec3 {1.0f, 2.0, 3.0f};
+ QVector4D vec4 {1.0f, 2.0f, 3.0f, 4.0f};
+#define ASJSON(NAME) {QLatin1String(#NAME), NAME}
+ comp.setInitialProperties(obj.get(), QVariantMap {
+ {QLatin1String("i"), 42},
+ {QLatin1String("b"), true},
+ {QLatin1String("d"), 3.1416},
+ {QLatin1String("s"), QLatin1String("hello world")},
+ {QLatin1String("nothing"), QVariant::fromValue( nullptr)},
+ ASJSON(myurl),
+ ASJSON(myfont),
+ ASJSON(mydate),
+ ASJSON(mypoint),
+ ASJSON(mysize),
+ ASJSON(matrix),
+ ASJSON(quat),
+ ASJSON(vec2), ASJSON(vec3), ASJSON(vec4)
+ });
+#undef ASJSON
+ comp.completeCreate();
+ if (!comp.errors().empty())
+ qDebug() << comp.errorString() << comp.errors();
+ QVERIFY(comp.errors().empty());
+ QCOMPARE(obj->property("i"), 42);
+ QCOMPARE(obj->property("b"), true);
+ QCOMPARE(obj->property("d"), 3.1416);
+ QCOMPARE(obj->property("s"), QLatin1String("hello world"));
+ QCOMPARE(obj->property("nothing"), QVariant::fromValue(nullptr));
+#define COMPARE(NAME) QCOMPARE(obj->property(#NAME), NAME)
+ COMPARE(myurl);
+ COMPARE(myfont);
+ COMPARE(mydate);
+ COMPARE(mypoint);
+ COMPARE(mysize);
+ COMPARE(matrix);
+ COMPARE(quat);
+ COMPARE(vec2);
+ COMPARE(vec3);
+ COMPARE(vec4);
+#undef COMPARE
+
+ }
+ {
+ // createWithInitialProperties: setting a nonexistent property
+ QQmlComponent comp(&eng);
+ comp.loadUrl(testFileUrl("allJSONTypes.qml"));
+ QScopedPointer<QObject> obj {
+ comp.createWithInitialProperties(QVariantMap { {"notThePropertiesYoureLookingFor", 42} })
+ };
+ qDebug() << comp.errorString();
+ QVERIFY(obj);
+ QVERIFY(comp.errorString().contains("Could not set property notThePropertiesYoureLookingFor"));
+ }
+}
+
QTEST_MAIN(tst_qqmlcomponent)
#include "tst_qqmlcomponent.moc"
diff --git a/tests/auto/qml/qqmlconnections/data/connection-no-signal-name.qml b/tests/auto/qml/qqmlconnections/data/bindings/connection-no-signal-name.qml
index 462a9577ff..462a9577ff 100644
--- a/tests/auto/qml/qqmlconnections/data/connection-no-signal-name.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/connection-no-signal-name.qml
diff --git a/tests/auto/qml/qqmlconnections/data/connection-targetchange.qml b/tests/auto/qml/qqmlconnections/data/bindings/connection-targetchange.qml
index 154c309c9c..154c309c9c 100644
--- a/tests/auto/qml/qqmlconnections/data/connection-targetchange.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/connection-targetchange.qml
diff --git a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals-ignored.qml b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-ignored.qml
index 0780dd1509..0780dd1509 100644
--- a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals-ignored.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-ignored.qml
diff --git a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals-notarget.qml b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-notarget.qml
index 3da3e0f5d1..3da3e0f5d1 100644
--- a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals-notarget.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-notarget.qml
diff --git a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals-parent.qml b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-parent.qml
index 2c55215579..2c55215579 100644
--- a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals-parent.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-parent.qml
diff --git a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals.qml b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals.qml
index a351016b4a..a351016b4a 100644
--- a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals.qml
diff --git a/tests/auto/qml/qqmlconnections/data/disabled-at-start.qml b/tests/auto/qml/qqmlconnections/data/bindings/disabled-at-start.qml
index 1a823f87f6..1a823f87f6 100644
--- a/tests/auto/qml/qqmlconnections/data/disabled-at-start.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/disabled-at-start.qml
diff --git a/tests/auto/qml/qqmlconnections/data/override-proxy-type.qml b/tests/auto/qml/qqmlconnections/data/bindings/override-proxy-type.qml
index 80e459966b..80e459966b 100644
--- a/tests/auto/qml/qqmlconnections/data/override-proxy-type.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/override-proxy-type.qml
diff --git a/tests/auto/qml/qqmlconnections/data/rewriteError-global.qml b/tests/auto/qml/qqmlconnections/data/bindings/rewriteError-global.qml
index 1d0b557069..1d0b557069 100644
--- a/tests/auto/qml/qqmlconnections/data/rewriteError-global.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/rewriteError-global.qml
diff --git a/tests/auto/qml/qqmlconnections/data/rewriteError-unnamed.qml b/tests/auto/qml/qqmlconnections/data/bindings/rewriteError-unnamed.qml
index a4849e994b..a4849e994b 100644
--- a/tests/auto/qml/qqmlconnections/data/rewriteError-unnamed.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/rewriteError-unnamed.qml
diff --git a/tests/auto/qml/qqmlconnections/data/singletontype-target.qml b/tests/auto/qml/qqmlconnections/data/bindings/singletontype-target.qml
index 7de488c2dd..7de488c2dd 100644
--- a/tests/auto/qml/qqmlconnections/data/singletontype-target.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/singletontype-target.qml
diff --git a/tests/auto/qml/qqmlconnections/data/test-connection-implicit.qml b/tests/auto/qml/qqmlconnections/data/bindings/test-connection-implicit.qml
index d5aa0f102a..d5aa0f102a 100644
--- a/tests/auto/qml/qqmlconnections/data/test-connection-implicit.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/test-connection-implicit.qml
diff --git a/tests/auto/qml/qqmlconnections/data/test-connection.qml b/tests/auto/qml/qqmlconnections/data/bindings/test-connection.qml
index f44cbc047f..f44cbc047f 100644
--- a/tests/auto/qml/qqmlconnections/data/test-connection.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/test-connection.qml
diff --git a/tests/auto/qml/qqmlconnections/data/trimming.qml b/tests/auto/qml/qqmlconnections/data/bindings/trimming.qml
index 4c37eb22af..4c37eb22af 100644
--- a/tests/auto/qml/qqmlconnections/data/trimming.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/trimming.qml
diff --git a/tests/auto/qml/qqmlconnections/data/functions/connection-no-signal-name.qml b/tests/auto/qml/qqmlconnections/data/functions/connection-no-signal-name.qml
new file mode 100644
index 0000000000..04cc36b3c5
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/connection-no-signal-name.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.4
+
+Item {
+ id: blaBlaBla
+ function hint() {
+ }
+
+ Connections {
+ //target: blaBlaBla
+ // function onHint() { hint() };
+ on: true
+ }
+}
+
+
diff --git a/tests/auto/qml/qqmlconnections/data/functions/connection-targetchange.qml b/tests/auto/qml/qqmlconnections/data/functions/connection-targetchange.qml
new file mode 100644
index 0000000000..692194e837
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/connection-targetchange.qml
@@ -0,0 +1,25 @@
+import QtQuick 2.0
+
+Item {
+ Component {
+ id: item1
+ Item {
+ objectName: "item1"
+ }
+ }
+ Component {
+ id: item2
+ Item {
+ objectName: "item2"
+ }
+ }
+ Loader {
+ id: loader
+ sourceComponent: item1
+ }
+ Connections {
+ objectName: "connections"
+ target: loader.item
+ function onWidthChanged() { loader.sourceComponent = item2 }
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-ignored.qml b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-ignored.qml
new file mode 100644
index 0000000000..f70d8cdb15
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-ignored.qml
@@ -0,0 +1,17 @@
+import QtQml 2.0
+
+QtObject {
+ id: root
+
+ property Connections c1: Connections {
+ target: root;
+ function onNotFooBar1() {}
+ ignoreUnknownSignals: true
+ }
+
+ property Connections c2: Connections {
+ objectName: "connections"
+ function onNotFooBar2() {}
+ ignoreUnknownSignals: true
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-notarget.qml b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-notarget.qml
new file mode 100644
index 0000000000..7658728dd9
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-notarget.qml
@@ -0,0 +1,9 @@
+import QtQml 2.0
+
+QtObject {
+ property Connections c1: Connections {
+ objectName: "connections"
+ target: null
+ function onNotFooBar() {}
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-parent.qml b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-parent.qml
new file mode 100644
index 0000000000..ece76b0cf7
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-parent.qml
@@ -0,0 +1,8 @@
+import QtQml 2.0
+
+QtObject {
+ property Connections c1: Connections {
+ objectName: "connections"
+ function onFooBar() {}
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals.qml b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals.qml
new file mode 100644
index 0000000000..a198a724d0
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals.qml
@@ -0,0 +1,11 @@
+import QtQml 2.0
+
+QtObject {
+ id: screen
+
+ property Connections c1: Connections {
+ objectName: "connections"
+ target: screen
+ function onFooBar() {}
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/disabled-at-start.qml b/tests/auto/qml/qqmlconnections/data/functions/disabled-at-start.qml
new file mode 100644
index 0000000000..981437fe8c
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/disabled-at-start.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.9
+
+Item {
+ id: root
+
+ property bool tested: false
+ signal testMe()
+
+ Connections {
+ target: root
+ enabled: false
+ function onTestMe() { root.tested = true; }
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/override-proxy-type.qml b/tests/auto/qml/qqmlconnections/data/functions/override-proxy-type.qml
new file mode 100644
index 0000000000..b83f0baa11
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/override-proxy-type.qml
@@ -0,0 +1,13 @@
+import QtQml 2.12
+import test.proxy 1.0
+
+Proxy {
+ property int testEnum: 0;
+ id: proxy
+ property Connections connections: Connections {
+ target: proxy
+ function onSomeSignal() { testEnum = Proxy.EnumValue }
+ }
+
+ Component.onCompleted: someSignal()
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/rewriteError-global.qml b/tests/auto/qml/qqmlconnections/data/functions/rewriteError-global.qml
new file mode 100644
index 0000000000..de3154c431
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/rewriteError-global.qml
@@ -0,0 +1,8 @@
+import QtQml 2.0
+import Test 1.0
+
+TestObject {
+ property QtObject connection: Connections {
+ function onSignalWithGlobalName() { ran = true }
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/rewriteError-unnamed.qml b/tests/auto/qml/qqmlconnections/data/functions/rewriteError-unnamed.qml
new file mode 100644
index 0000000000..fa1d1b17d7
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/rewriteError-unnamed.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+import Test 1.0
+
+TestObject {
+ property QtObject connection: Connections {
+ function onUnnamedArgumentSignal() { ran = true }
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/singletontype-target.qml b/tests/auto/qml/qqmlconnections/data/functions/singletontype-target.qml
new file mode 100644
index 0000000000..935b610351
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/singletontype-target.qml
@@ -0,0 +1,22 @@
+import QtQml 2.0
+import MyTestSingletonType 1.0 as MyTestSingletonType
+
+QtObject {
+ id: rootObject
+ objectName: "rootObject"
+ property int newIntPropValue: 12
+
+ property int moduleIntPropChangedCount: 0
+ property int moduleOtherSignalCount: 0
+
+ function setModuleIntProp() {
+ MyTestSingletonType.Api.intProp = newIntPropValue;
+ newIntPropValue = newIntPropValue + 1;
+ }
+
+ property Connections c: Connections {
+ target: MyTestSingletonType.Api
+ function onIntPropChanged() { moduleIntPropChangedCount = moduleIntPropChangedCount + 1 }
+ function onOtherSignal() { moduleOtherSignalCount = moduleOtherSignalCount + 1 }
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/test-connection-implicit.qml b/tests/auto/qml/qqmlconnections/data/functions/test-connection-implicit.qml
new file mode 100644
index 0000000000..2ed5278636
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/test-connection-implicit.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+Item {
+ width: 50
+
+ property bool tested: false
+
+ Connections { function onWidthChanged() { tested = true } }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/test-connection.qml b/tests/auto/qml/qqmlconnections/data/functions/test-connection.qml
new file mode 100644
index 0000000000..c706797ea4
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/test-connection.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+Item {
+ id: screen; width: 50
+
+ property bool tested: false
+ signal testMe
+
+ Connections {
+ objectName: "connections"
+ target: screen;
+ function onWidthChanged() { screen.tested = true }
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/trimming.qml b/tests/auto/qml/qqmlconnections/data/functions/trimming.qml
new file mode 100644
index 0000000000..7dfd673539
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/trimming.qml
@@ -0,0 +1,13 @@
+import QtQml 2.0
+
+QtObject {
+ id: root
+
+ property string tested
+ signal testMe(int param1, string param2)
+
+ property Connections c: Connections {
+ target: root
+ function onTestMe(param1, param2) { root.tested = param2 + param1 }
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp
index 7e6a0f79f9..cf0f3c7bb3 100644
--- a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp
+++ b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp
@@ -42,29 +42,57 @@ public:
private slots:
void defaultValues();
void properties();
+
+ void connection_data() { prefixes(); }
void connection();
+
+ void trimming_data() { prefixes(); }
void trimming();
+
+ void targetChanged_data() { prefixes(); };
void targetChanged();
+
void unknownSignals_data();
void unknownSignals();
+
void errors_data();
void errors();
+
+ void rewriteErrors_data() { prefixes(); }
void rewriteErrors();
+
+ void singletonTypeTarget_data() { prefixes(); }
void singletonTypeTarget();
+
+ void enableDisable_QTBUG_36350_data() { prefixes(); }
void enableDisable_QTBUG_36350();
+
+ void disabledAtStart_data() { prefixes(); }
void disabledAtStart();
+
+ void clearImplicitTarget_data() { prefixes(); }
void clearImplicitTarget();
void onWithoutASignal();
+
+ void noAcceleratedGlobalLookup_data() { prefixes(); }
void noAcceleratedGlobalLookup();
private:
QQmlEngine engine;
+ void prefixes();
};
tst_qqmlconnections::tst_qqmlconnections()
{
}
+void tst_qqmlconnections::prefixes()
+{
+ QTest::addColumn<QString>("prefix");
+ QTest::newRow("functions") << QString("functions");
+ QTest::newRow("bindings") << QString("bindings");
+}
+
void tst_qqmlconnections::defaultValues()
{
QQmlEngine engine;
@@ -93,8 +121,9 @@ void tst_qqmlconnections::properties()
void tst_qqmlconnections::connection()
{
+ QFETCH(QString, prefix);
QQmlEngine engine;
- QQmlComponent c(&engine, testFileUrl("test-connection.qml"));
+ QQmlComponent c(&engine, testFileUrl(prefix + "/test-connection.qml"));
QQuickItem *item = qobject_cast<QQuickItem*>(c.create());
QVERIFY(item != nullptr);
@@ -110,8 +139,9 @@ void tst_qqmlconnections::connection()
void tst_qqmlconnections::trimming()
{
+ QFETCH(QString, prefix);
QQmlEngine engine;
- QQmlComponent c(&engine, testFileUrl("trimming.qml"));
+ QQmlComponent c(&engine, testFileUrl(prefix + "/trimming.qml"));
QObject *object = c.create();
QVERIFY(object != nullptr);
@@ -131,8 +161,9 @@ void tst_qqmlconnections::trimming()
// Confirm that target can be changed by one of our signal handlers
void tst_qqmlconnections::targetChanged()
{
+ QFETCH(QString, prefix);
QQmlEngine engine;
- QQmlComponent c(&engine, testFileUrl("connection-targetchange.qml"));
+ QQmlComponent c(&engine, testFileUrl(prefix + "/connection-targetchange.qml"));
QQuickItem *item = qobject_cast<QQuickItem*>(c.create());
QVERIFY(item != nullptr);
@@ -158,10 +189,15 @@ void tst_qqmlconnections::unknownSignals_data()
QTest::addColumn<QString>("file");
QTest::addColumn<QString>("error");
- QTest::newRow("basic") << "connection-unknownsignals.qml" << ":6:30: QML Connections: Cannot assign to non-existent property \"onFooBar\"";
- QTest::newRow("parent") << "connection-unknownsignals-parent.qml" << ":4:30: QML Connections: Cannot assign to non-existent property \"onFooBar\"";
- QTest::newRow("ignored") << "connection-unknownsignals-ignored.qml" << ""; // should be NO error
- QTest::newRow("notarget") << "connection-unknownsignals-notarget.qml" << ""; // should be NO error
+ QTest::newRow("functions/basic") << "functions/connection-unknownsignals.qml" << ":6:30: QML Connections: Detected function \"onFooBar\" in Connections element. This is probably intended to be a signal handler but no signal of the target matches the name.";
+ QTest::newRow("functions/parent") << "functions/connection-unknownsignals-parent.qml" << ":4:30: QML Connections: Detected function \"onFooBar\" in Connections element. This is probably intended to be a signal handler but no signal of the target matches the name.";
+ QTest::newRow("functions/ignored") << "functions/connection-unknownsignals-ignored.qml" << ""; // should be NO error
+ QTest::newRow("functions/notarget") << "functions/connection-unknownsignals-notarget.qml" << ""; // should be NO error
+
+ QTest::newRow("bindings/basic") << "bindings/connection-unknownsignals.qml" << ":6:30: QML Connections: Cannot assign to non-existent property \"onFooBar\"";
+ QTest::newRow("bindings/parent") << "bindings/connection-unknownsignals-parent.qml" << ":4:30: QML Connections: Cannot assign to non-existent property \"onFooBar\"";
+ QTest::newRow("bindings/ignored") << "bindings/connection-unknownsignals-ignored.qml" << ""; // should be NO error
+ QTest::newRow("bindings/notarget") << "bindings/connection-unknownsignals-notarget.qml" << ""; // should be NO error
}
void tst_qqmlconnections::unknownSignals()
@@ -239,10 +275,11 @@ private:
void tst_qqmlconnections::rewriteErrors()
{
+ QFETCH(QString, prefix);
qmlRegisterType<TestObject>("Test", 1, 0, "TestObject");
{
QQmlEngine engine;
- QQmlComponent c(&engine, testFileUrl("rewriteError-unnamed.qml"));
+ QQmlComponent c(&engine, testFileUrl(prefix + "/rewriteError-unnamed.qml"));
QTest::ignoreMessage(QtWarningMsg, (c.url().toString() + ":5:35: QML Connections: Signal uses unnamed parameter followed by named parameter.").toLatin1());
TestObject *obj = qobject_cast<TestObject*>(c.create());
QVERIFY(obj != nullptr);
@@ -254,7 +291,7 @@ void tst_qqmlconnections::rewriteErrors()
{
QQmlEngine engine;
- QQmlComponent c(&engine, testFileUrl("rewriteError-global.qml"));
+ QQmlComponent c(&engine, testFileUrl(prefix + "/rewriteError-global.qml"));
QTest::ignoreMessage(QtWarningMsg, (c.url().toString() + ":5:35: QML Connections: Signal parameter \"parseInt\" hides global variable.").toLatin1());
TestObject *obj = qobject_cast<TestObject*>(c.create());
QVERIFY(obj != nullptr);
@@ -305,8 +342,9 @@ static QObject *module_api_factory(QQmlEngine *engine, QJSEngine *scriptEngine)
// QTBUG-20937
void tst_qqmlconnections::singletonTypeTarget()
{
+ QFETCH(QString, prefix);
qmlRegisterSingletonType<MyTestSingletonType>("MyTestSingletonType", 1, 0, "Api", module_api_factory);
- QQmlComponent component(&engine, testFileUrl("singletontype-target.qml"));
+ QQmlComponent component(&engine, testFileUrl(prefix + "/singletontype-target.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -331,8 +369,9 @@ void tst_qqmlconnections::singletonTypeTarget()
void tst_qqmlconnections::enableDisable_QTBUG_36350()
{
+ QFETCH(QString, prefix);
QQmlEngine engine;
- QQmlComponent c(&engine, testFileUrl("test-connection.qml"));
+ QQmlComponent c(&engine, testFileUrl(prefix + "/test-connection.qml"));
QQuickItem *item = qobject_cast<QQuickItem*>(c.create());
QVERIFY(item != nullptr);
@@ -358,8 +397,9 @@ void tst_qqmlconnections::enableDisable_QTBUG_36350()
void tst_qqmlconnections::disabledAtStart()
{
+ QFETCH(QString, prefix);
QQmlEngine engine;
- QQmlComponent c(&engine, testFileUrl("disabled-at-start.qml"));
+ QQmlComponent c(&engine, testFileUrl(prefix + "/disabled-at-start.qml"));
QObject * const object = c.create();
QVERIFY(object != nullptr);
@@ -376,8 +416,9 @@ void tst_qqmlconnections::disabledAtStart()
//QTBUG-56499
void tst_qqmlconnections::clearImplicitTarget()
{
+ QFETCH(QString, prefix);
QQmlEngine engine;
- QQmlComponent c(&engine, testFileUrl("test-connection-implicit.qml"));
+ QQmlComponent c(&engine, testFileUrl(prefix + "/test-connection-implicit.qml"));
QQuickItem *item = qobject_cast<QQuickItem*>(c.create());
QVERIFY(item != nullptr);
@@ -421,10 +462,11 @@ signals:
void tst_qqmlconnections::noAcceleratedGlobalLookup()
{
+ QFETCH(QString, prefix);
qRegisterMetaType<Proxy::MyEnum>();
qmlRegisterType<Proxy>("test.proxy", 1, 0, "Proxy");
QQmlEngine engine;
- QQmlComponent c(&engine, testFileUrl("override-proxy-type.qml"));
+ QQmlComponent c(&engine, testFileUrl(prefix + "/override-proxy-type.qml"));
QVERIFY(c.isReady());
QScopedPointer<QObject> object(c.create());
const QVariant val = object->property("testEnum");
diff --git a/tests/auto/qml/qqmlecmascript/data/semicolonAfterProperty.qml b/tests/auto/qml/qqmlecmascript/data/semicolonAfterProperty.qml
new file mode 100644
index 0000000000..0a75ea6f36
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/semicolonAfterProperty.qml
@@ -0,0 +1,10 @@
+import QtQml 2.0
+
+QtObject {
+ property var field: { "key": "value"};
+ property list<QtObject> mylist: [
+ QtObject {id: a},
+ QtObject {id: b}
+ ];
+ property var object: QtObject {};
+}
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index b44fe9766c..269d90c891 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -374,6 +374,7 @@ private slots:
void hugeRegexpQuantifiers();
void singletonTypeWrapperLookup();
void getThisObject();
+ void semicolonAfterProperty();
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
@@ -9106,6 +9107,16 @@ void tst_qqmlecmascript::getThisObject()
QTRY_COMPARE(qvariant_cast<QObject *>(test->property("self")), test.data());
}
+// QTBUG-77954
+void tst_qqmlecmascript::semicolonAfterProperty()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("semicolonAfterProperty.qml"));
+ QVERIFY(component.isReady());
+ QScopedPointer<QObject> test(component.create());
+ QVERIFY(!test.isNull());
+}
+
QTEST_MAIN(tst_qqmlecmascript)
#include "tst_qqmlecmascript.moc"
diff --git a/tests/auto/qml/qqmllanguage/data/propertyUnknownType.errors.txt b/tests/auto/qml/qqmllanguage/data/propertyUnknownType.errors.txt
new file mode 100644
index 0000000000..1655f9264a
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/propertyUnknownType.errors.txt
@@ -0,0 +1 @@
+3:23:Cannot assign to property of unknown type "SomethingUnknown*".
diff --git a/tests/auto/qml/qqmllanguage/data/propertyUnknownType.qml b/tests/auto/qml/qqmllanguage/data/propertyUnknownType.qml
new file mode 100644
index 0000000000..c22fd65350
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/propertyUnknownType.qml
@@ -0,0 +1,4 @@
+import Test 1.0
+MyQmlObject {
+ somethingUnknown: SomethingKnown {}
+}
diff --git a/tests/auto/qml/qqmllanguage/qqmllanguage.pro b/tests/auto/qml/qqmllanguage/qqmllanguage.pro
index 3e88f3f0db..724a27320c 100644
--- a/tests/auto/qml/qqmllanguage/qqmllanguage.pro
+++ b/tests/auto/qml/qqmllanguage/qqmllanguage.pro
@@ -17,3 +17,5 @@ include (../../shared/util.pri)
OTHER_FILES += \
data/readonlyObjectProperty.qml
+
+android: RESOURCES += qqmllanguage.qrc
diff --git a/tests/auto/qml/qqmllanguage/qqmllanguage.qrc b/tests/auto/qml/qqmllanguage/qqmllanguage.qrc
new file mode 100644
index 0000000000..f5212ac75c
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/qqmllanguage.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/">
+<file alias="data/I18nTypeÁâãäå.qml">data/I18nType30.qml</file>
+</qresource>
+</RCC>
diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp
index ffb1d51971..6956533196 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.cpp
+++ b/tests/auto/qml/qqmllanguage/testtypes.cpp
@@ -62,6 +62,7 @@ void registerTypes()
qmlRegisterType<MyRevisionedClass,1>("Test",1,1,"MyRevisionedClass");
qmlRegisterType<MyRevisionedIllegalOverload>("Test",1,0,"MyRevisionedIllegalOverload");
qmlRegisterType<MyRevisionedLegalOverload>("Test",1,0,"MyRevisionedLegalOverload");
+ qmlRegisterType<SomethingKnown>("Test",1,0,"SomethingKnown");
// Register the uncreatable base class
qmlRegisterRevision<MyRevisionedBaseClassRegistered,1>("Test",1,1);
diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h
index 0618d2b20f..1aab24841a 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.h
+++ b/tests/auto/qml/qqmllanguage/testtypes.h
@@ -89,6 +89,14 @@ private:
int m_value2;
};
+class SomethingUnknown : public QObject {
+ Q_OBJECT
+};
+
+class SomethingKnown : public SomethingUnknown {
+ Q_OBJECT
+};
+
class MyQmlObject : public QObject, public MyInterface
{
Q_OBJECT
@@ -104,6 +112,7 @@ class MyQmlObject : public QObject, public MyInterface
Q_PROPERTY(int propertyWithNotify READ propertyWithNotify WRITE setPropertyWithNotify NOTIFY oddlyNamedNotifySignal)
Q_PROPERTY(int nonScriptable READ nonScriptable WRITE setNonScriptable SCRIPTABLE false)
Q_PROPERTY(QJSValue qjsvalue READ qjsvalue WRITE setQJSValue NOTIFY qjsvalueChanged)
+ Q_PROPERTY(SomethingUnknown* somethingUnknown READ somethingUnknown WRITE setSomethingUnknown NOTIFY somethingUnknownChanged)
Q_INTERFACES(MyInterface)
public:
@@ -151,6 +160,9 @@ public:
int childAddedEventCount() const { return m_childAddedEventCount; }
+ SomethingUnknown* somethingUnknown() const { return nullptr; }
+ void setSomethingUnknown(SomethingUnknown* something) { Q_UNUSED(something); }
+
public slots:
void basicSlot() { qWarning("MyQmlObject::basicSlot"); }
void basicSlotWithArgs(int v) { qWarning("MyQmlObject::basicSlotWithArgs(%d)", v); }
@@ -162,6 +174,7 @@ signals:
void oddlyNamedNotifySignal();
void signalWithDefaultArg(int parameter = 5);
void qjsvalueChanged();
+ void somethingUnknownChanged();
protected:
virtual bool event(QEvent *event);
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index a54c4b35d4..8adacd8829 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -370,7 +370,8 @@ private:
void tst_qqmllanguage::cleanupTestCase()
{
- QVERIFY(QFile::remove(testFile(QString::fromUtf8("I18nType\303\201\303\242\303\243\303\244\303\245.qml"))));
+ if (dataDirectoryUrl().scheme() != QLatin1String("qrc"))
+ QVERIFY(QFile::remove(testFile(QString::fromUtf8("I18nType\303\201\303\242\303\243\303\244\303\245.qml"))));
}
void tst_qqmllanguage::insertedSemicolon_data()
@@ -625,11 +626,24 @@ void tst_qqmllanguage::errors_data()
QTest::newRow("bareQmlImport") << "bareQmlImport.qml" << "bareQmlImport.errors.txt" << false;
QTest::newRow("typeAnnotations.2") << "typeAnnotations.2.qml" << "typeAnnotations.2.errors.txt" << false;
-}
+ QTest::newRow("propertyUnknownType") << "propertyUnknownType.qml" << "propertyUnknownType.errors.txt" << false;
+}
void tst_qqmllanguage::errors()
{
+#ifdef Q_OS_ANDROID
+ if (qstrcmp(QTest::currentDataTag(), "fuzzed.2") == 0) {
+ QSKIP("Gives different errors on Android");
+ /* Only gives one error on Android:
+
+ qrc:/data/fuzzed.2.qml:1:1: "
+ import"
+ ^
+ So, it seems to complain about the first import (which is understandable)
+ */
+ }
+#endif
QFETCH(QString, file);
QFETCH(QString, errorFile);
QFETCH(bool, create);
@@ -2678,11 +2692,15 @@ void tst_qqmllanguage::importsLocal_data()
"Test {}"
<< (!qmlCheckTypes()?"TestType":"")
<< (!qmlCheckTypes()?"":"Test is ambiguous. Found in org/qtproject/Test/ and in subdir/");
- QTest::newRow("file URL survives percent-encoding")
- << "import \"" + QUrl::fromLocalFile(QDir::currentPath() + "/{subdir}").toString() + "\"\n"
- "Test {}"
- << "QQuickRectangle"
- << "";
+
+ if (dataDirectoryUrl().scheme() != QLatin1String("qrc")) {
+ // file URL doesn't work with qrc scheme
+ QTest::newRow("file URL survives percent-encoding")
+ << "import \"" + QUrl::fromLocalFile(QDir::currentPath() + "/{subdir}").toString() + "\"\n"
+ "Test {}"
+ << "QQuickRectangle"
+ << "";
+ }
}
void tst_qqmllanguage::importsLocal()
@@ -3441,7 +3459,11 @@ void tst_qqmllanguage::uncreatableTypesAsProperties()
void tst_qqmllanguage::initTestCase()
{
QQmlDataTest::initTestCase();
- QVERIFY2(QDir::setCurrent(dataDirectory()), qPrintable("Could not chdir to " + dataDirectory()));
+ if (dataDirectoryUrl().scheme() == QLatin1String("qrc"))
+ engine.addImportPath(dataDirectory());
+ else
+ QVERIFY2(QDir::setCurrent(dataDirectory()), qPrintable("Could not chdir to " + dataDirectory()));
+
defaultImportPathList = engine.importPathList();
@@ -3472,11 +3494,13 @@ void tst_qqmllanguage::initTestCase()
// For POSIX, this will just be data/I18nType.qml, since POSIX is 7-bit
// For iso8859-1 locale, this will just be data/I18nType?????.qml where ????? is 5 8-bit characters
// For utf-8 locale, this will be data/I18nType??????????.qml where ?????????? is 5 8-bit characters, UTF-8 encoded
- QFile in(testFileUrl(QLatin1String("I18nType30.qml")).toLocalFile());
- QVERIFY2(in.open(QIODevice::ReadOnly), qPrintable(QString::fromLatin1("Cannot open '%1': %2").arg(in.fileName(), in.errorString())));
- QFile out(testFileUrl(QString::fromUtf8("I18nType\303\201\303\242\303\243\303\244\303\245.qml")).toLocalFile());
- QVERIFY2(out.open(QIODevice::WriteOnly), qPrintable(QString::fromLatin1("Cannot open '%1': %2").arg(out.fileName(), out.errorString())));
- out.write(in.readAll());
+ if (dataDirectoryUrl().scheme() != QLatin1String("qrc")) {
+ QFile in(testFileUrl(QLatin1String("I18nType30.qml")).toLocalFile());
+ QVERIFY2(in.open(QIODevice::ReadOnly), qPrintable(QString::fromLatin1("Cannot open '%1': %2").arg(in.fileName(), in.errorString())));
+ QFile out(testFileUrl(QString::fromUtf8("I18nType\303\201\303\242\303\243\303\244\303\245.qml")).toLocalFile());
+ QVERIFY2(out.open(QIODevice::WriteOnly), qPrintable(QString::fromLatin1("Cannot open '%1': %2").arg(out.fileName(), out.errorString())));
+ out.write(in.readAll());
+ }
// Register a Composite Singleton.
qmlRegisterSingletonType(testFileUrl("singleton/RegisteredCompositeSingletonType.qml"), "org.qtproject.Test", 1, 0, "RegisteredSingleton");
@@ -3988,7 +4012,7 @@ void tst_qqmllanguage::objectDeletionNotify()
void tst_qqmllanguage::scopedProperties()
{
- QQmlComponent component(&engine, testFile("scopedProperties.qml"));
+ QQmlComponent component(&engine, testFileUrl("scopedProperties.qml"));
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -3997,7 +4021,7 @@ void tst_qqmllanguage::scopedProperties()
void tst_qqmllanguage::deepProperty()
{
- QQmlComponent component(&engine, testFile("deepProperty.qml"));
+ QQmlComponent component(&engine, testFileUrl("deepProperty.qml"));
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
QFont font = qvariant_cast<QFont>(qvariant_cast<QObject*>(o->property("someObject"))->property("font"));
@@ -4015,7 +4039,7 @@ void tst_qqmllanguage::implicitImportsLast()
if (engine.importPathList() == defaultImportPathList)
engine.addImportPath(testFile("lib"));
- QQmlComponent component(&engine, testFile("localOrderTest.qml"));
+ QQmlComponent component(&engine, testFileUrl("localOrderTest.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
@@ -4035,7 +4059,7 @@ void tst_qqmllanguage::getSingletonInstance(QQmlEngine& engine, const char* file
if (!fileName || !propertyName)
return;
- QQmlComponent component(&engine, testFile(fileName));
+ QQmlComponent component(&engine, testFileUrl(fileName));
VERIFY_ERRORS(0);
QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
@@ -4077,7 +4101,7 @@ void verifyCompositeSingletonPropertyValues(QObject* o, const char* n1, int v1,
// Reads values from a composite singleton type
void tst_qqmllanguage::compositeSingletonProperties()
{
- QQmlComponent component(&engine, testFile("singletonTest1.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest1.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -4124,14 +4148,14 @@ void tst_qqmllanguage::compositeSingletonDifferentEngine()
// pragma Singleton in a non-type qml file fails
void tst_qqmllanguage::compositeSingletonNonTypeError()
{
- QQmlComponent component(&engine, testFile("singletonTest4.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest4.qml"));
VERIFY_ERRORS("singletonTest4.error.txt");
}
// Loads the singleton using a namespace qualifier
void tst_qqmllanguage::compositeSingletonQualifiedNamespace()
{
- QQmlComponent component(&engine, testFile("singletonTest5.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest5.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -4156,7 +4180,7 @@ void tst_qqmllanguage::compositeSingletonModule()
{
engine.addImportPath(testFile("singleton/module"));
- QQmlComponent component(&engine, testFile("singletonTest6.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest6.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -4182,7 +4206,7 @@ void tst_qqmllanguage::compositeSingletonModuleVersioned()
{
engine.addImportPath(testFile("singleton/module"));
- QQmlComponent component(&engine, testFile("singletonTest7.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest7.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -4208,7 +4232,7 @@ void tst_qqmllanguage::compositeSingletonModuleQualified()
{
engine.addImportPath(testFile("singleton/module"));
- QQmlComponent component(&engine, testFile("singletonTest8.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest8.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -4232,14 +4256,14 @@ void tst_qqmllanguage::compositeSingletonModuleQualified()
// Tries to instantiate a type with a pragma Singleton and fails
void tst_qqmllanguage::compositeSingletonInstantiateError()
{
- QQmlComponent component(&engine, testFile("singletonTest9.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest9.qml"));
VERIFY_ERRORS("singletonTest9.error.txt");
}
// Having a composite singleton type as dynamic property type is allowed
void tst_qqmllanguage::compositeSingletonDynamicPropertyError()
{
- QQmlComponent component(&engine, testFile("singletonTest10.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest10.qml"));
VERIFY_ERRORS(0);
}
@@ -4247,7 +4271,7 @@ void tst_qqmllanguage::compositeSingletonDynamicPropertyError()
// (like C++ singleton)
void tst_qqmllanguage::compositeSingletonDynamicSignal()
{
- QQmlComponent component(&engine, testFile("singletonTest11.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest11.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -4261,21 +4285,21 @@ void tst_qqmllanguage::compositeSingletonQmlRegisterTypeError()
{
qmlRegisterType(testFileUrl("singleton/registeredComposite/CompositeType.qml"),
"CompositeSingletonTest", 1, 0, "RegisteredCompositeType");
- QQmlComponent component(&engine, testFile("singletonTest12.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest12.qml"));
VERIFY_ERRORS("singletonTest12.error.txt");
}
// Qmldir defines a type as a singleton, but the qml file does not have a pragma Singleton.
void tst_qqmllanguage::compositeSingletonQmldirNoPragmaError()
{
- QQmlComponent component(&engine, testFile("singletonTest13.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest13.qml"));
VERIFY_ERRORS("singletonTest13.error.txt");
}
// Invalid singleton definition in the qmldir file results in an error
void tst_qqmllanguage::compositeSingletonQmlDirError()
{
- QQmlComponent component(&engine, testFile("singletonTest14.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest14.qml"));
VERIFY_ERRORS("singletonTest14.error.txt");
}
@@ -4309,7 +4333,7 @@ void tst_qqmllanguage::compositeSingletonRemote()
// the pragma Singleton changes.
void tst_qqmllanguage::compositeSingletonJavaScriptPragma()
{
- QQmlComponent component(&engine, testFile("singletonTest16.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest16.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -4327,7 +4351,7 @@ void tst_qqmllanguage::compositeSingletonSelectors()
QQmlEngine e2;
QQmlFileSelector qmlSelector(&e2);
qmlSelector.setExtraSelectors(QStringList() << "basicSelector");
- QQmlComponent component(&e2, testFile("singletonTest1.qml"));
+ QQmlComponent component(&e2, testFileUrl("singletonTest1.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -4339,7 +4363,7 @@ void tst_qqmllanguage::compositeSingletonSelectors()
// qmlRegisterSingletonType.
void tst_qqmllanguage::compositeSingletonRegistered()
{
- QQmlComponent component(&engine, testFile("singletonTest17.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest17.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -4349,7 +4373,7 @@ void tst_qqmllanguage::compositeSingletonRegistered()
void tst_qqmllanguage::compositeSingletonCircular()
{
- QQmlComponent component(&engine, testFile("circularSingleton.qml"));
+ QQmlComponent component(&engine, testFileUrl("circularSingleton.qml"));
VERIFY_ERRORS(0);
QQmlTestMessageHandler messageHandler;
@@ -4383,7 +4407,7 @@ void tst_qqmllanguage::singletonsHaveContextAndEngine()
void tst_qqmllanguage::customParserBindingScopes()
{
- QQmlComponent component(&engine, testFile("customParserBindingScopes.qml"));
+ QQmlComponent component(&engine, testFileUrl("customParserBindingScopes.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(!o.isNull());
@@ -4394,7 +4418,7 @@ void tst_qqmllanguage::customParserBindingScopes()
void tst_qqmllanguage::customParserEvaluateEnum()
{
- QQmlComponent component(&engine, testFile("customParserEvaluateEnum.qml"));
+ QQmlComponent component(&engine, testFileUrl("customParserEvaluateEnum.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(!o.isNull());
@@ -4402,7 +4426,7 @@ void tst_qqmllanguage::customParserEvaluateEnum()
void tst_qqmllanguage::customParserProperties()
{
- QQmlComponent component(&engine, testFile("customParserProperties.qml"));
+ QQmlComponent component(&engine, testFileUrl("customParserProperties.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(!o.isNull());
@@ -4416,7 +4440,7 @@ void tst_qqmllanguage::customParserProperties()
void tst_qqmllanguage::customParserWithExtendedObject()
{
- QQmlComponent component(&engine, testFile("customExtendedParserProperties.qml"));
+ QQmlComponent component(&engine, testFileUrl("customExtendedParserProperties.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(!o.isNull());
@@ -4434,7 +4458,7 @@ void tst_qqmllanguage::customParserWithExtendedObject()
void tst_qqmllanguage::nestedCustomParsers()
{
- QQmlComponent component(&engine, testFile("nestedCustomParsers.qml"));
+ QQmlComponent component(&engine, testFileUrl("nestedCustomParsers.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(!o.isNull());
@@ -4448,7 +4472,7 @@ void tst_qqmllanguage::nestedCustomParsers()
void tst_qqmllanguage::preservePropertyCacheOnGroupObjects()
{
- QQmlComponent component(&engine, testFile("preservePropertyCacheOnGroupObjects.qml"));
+ QQmlComponent component(&engine, testFileUrl("preservePropertyCacheOnGroupObjects.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(!o.isNull());
@@ -4467,7 +4491,7 @@ void tst_qqmllanguage::preservePropertyCacheOnGroupObjects()
void tst_qqmllanguage::propertyCacheInSync()
{
- QQmlComponent component(&engine, testFile("propertyCacheInSync.qml"));
+ QQmlComponent component(&engine, testFileUrl("propertyCacheInSync.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(!o.isNull());
@@ -4487,7 +4511,7 @@ void tst_qqmllanguage::propertyCacheInSync()
void tst_qqmllanguage::rootObjectInCreationNotForSubObjects()
{
- QQmlComponent component(&engine, testFile("rootObjectInCreationNotForSubObjects.qml"));
+ QQmlComponent component(&engine, testFileUrl("rootObjectInCreationNotForSubObjects.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(!o.isNull());
@@ -4513,7 +4537,7 @@ void tst_qqmllanguage::rootObjectInCreationNotForSubObjects()
// QTBUG-63036
void tst_qqmllanguage::lazyDeferredSubObject()
{
- QQmlComponent component(&engine, testFile("lazyDeferredSubObject.qml"));
+ QQmlComponent component(&engine, testFileUrl("lazyDeferredSubObject.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -4528,7 +4552,7 @@ void tst_qqmllanguage::lazyDeferredSubObject()
// QTBUG-63200
void tst_qqmllanguage::deferredProperties()
{
- QQmlComponent component(&engine, testFile("deferredProperties.qml"));
+ QQmlComponent component(&engine, testFileUrl("deferredProperties.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -4645,7 +4669,7 @@ static void testExecuteDeferredOnce(const QQmlProperty &property)
void tst_qqmllanguage::executeDeferredPropertiesOnce()
{
- QQmlComponent component(&engine, testFile("deferredProperties.qml"));
+ QQmlComponent component(&engine, testFileUrl("deferredProperties.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -4745,7 +4769,7 @@ void tst_qqmllanguage::deleteSingletons()
QPointer<QObject> singleton;
{
QQmlEngine tmpEngine;
- QQmlComponent component(&tmpEngine, testFile("singletonTest5.qml"));
+ QQmlComponent component(&tmpEngine, testFileUrl("singletonTest5.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -4772,7 +4796,7 @@ void tst_qqmllanguage::arrayBuffer_data()
void tst_qqmllanguage::arrayBuffer()
{
QFETCH(QString, file);
- QQmlComponent component(&engine, testFile(file));
+ QQmlComponent component(&engine, testFileUrl(file));
VERIFY_ERRORS(0);
QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
diff --git a/tests/auto/qml/qqmlpropertymap/dummy_imports.qml b/tests/auto/qml/qqmlpropertymap/dummy_imports.qml
new file mode 100644
index 0000000000..4ae9d3f2cf
--- /dev/null
+++ b/tests/auto/qml/qqmlpropertymap/dummy_imports.qml
@@ -0,0 +1,8 @@
+// This file exists for the sole purpose for qmlimportscanner to find
+// which modules it needs to extract for deployment.
+// Otherwise, it fails to find the imports that are expressed in the
+// C++ code belonging to the test.
+
+import QtQuick 2.0
+
+QtObject { } // This is needed in order to keep importscanner happy
diff --git a/tests/auto/qml/qqmlpropertymap/qqmlpropertymap.pro b/tests/auto/qml/qqmlpropertymap/qqmlpropertymap.pro
index 8da300171d..b83e1e0da2 100644
--- a/tests/auto/qml/qqmlpropertymap/qqmlpropertymap.pro
+++ b/tests/auto/qml/qqmlpropertymap/qqmlpropertymap.pro
@@ -7,3 +7,5 @@ SOURCES += tst_qqmlpropertymap.cpp
include (../../shared/util.pri)
QT += core-private gui-private qml-private quick-private testlib
+
+TESTDATA = data/*
diff --git a/tests/auto/qml/qqmlsqldatabase/dummy_imports.qml b/tests/auto/qml/qqmlsqldatabase/dummy_imports.qml
new file mode 100644
index 0000000000..4ae9d3f2cf
--- /dev/null
+++ b/tests/auto/qml/qqmlsqldatabase/dummy_imports.qml
@@ -0,0 +1,8 @@
+// This file exists for the sole purpose for qmlimportscanner to find
+// which modules it needs to extract for deployment.
+// Otherwise, it fails to find the imports that are expressed in the
+// C++ code belonging to the test.
+
+import QtQuick 2.0
+
+QtObject { } // This is needed in order to keep importscanner happy
diff --git a/tests/auto/qml/qqmltimer/dummy_imports.qml b/tests/auto/qml/qqmltimer/dummy_imports.qml
new file mode 100644
index 0000000000..f78e04d489
--- /dev/null
+++ b/tests/auto/qml/qqmltimer/dummy_imports.qml
@@ -0,0 +1,9 @@
+// This file exists for the sole purpose for qmlimportscanner to find
+// which modules it needs to extract for deployment.
+// Otherwise, it fails to find the imports that are expressed in the
+// C++ code belonging to the test.
+
+import QtQml 2.0
+import QtQuick 2.0
+
+QtObject { } // This is needed in order to keep importscanner happy
diff --git a/tests/auto/qml/qqmltypeloader/dummy_imports.qml b/tests/auto/qml/qqmltypeloader/dummy_imports.qml
new file mode 100644
index 0000000000..a4684b2007
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/dummy_imports.qml
@@ -0,0 +1,9 @@
+// This file exists for the sole purpose for qmlimportscanner to find
+// which modules it needs to extract for deployment.
+// Otherwise, it fails to find the imports that are expressed in the
+// C++ code belonging to the test.
+
+import QtQml 2.0
+import QtQuick 2.6
+
+QtObject { } // This is needed in order to keep importscanner happy
diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
index 2993b4b3c8..63a43eebad 100644
--- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
+++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
@@ -60,10 +60,16 @@ private slots:
void implicitComponentModule();
void qrcRootPathUrl();
void implicitImport();
+
+private:
+ void checkSingleton(const QString & dataDirectory);
};
void tst_QQMLTypeLoader::testLoadComplete()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("Loading dynamic plugins does not work on Android");
+#endif
QQuickView *window = new QQuickView();
window->engine()->addImportPath(QT_TESTCASE_BUILDDIR);
qDebug() << window->engine()->importPathList();
@@ -157,7 +163,7 @@ void tst_QQMLTypeLoader::trimCache3()
QCOMPARE(loader.isTypeLoaded(testFileUrl("ComponentWithIncubator.qml")), false);
}
-static void checkSingleton(const QString &dataDirectory)
+void tst_QQMLTypeLoader::checkSingleton(const QString &dataDirectory)
{
QQmlEngine engine;
engine.addImportPath(dataDirectory);
@@ -166,8 +172,8 @@ static void checkSingleton(const QString &dataDirectory)
"import QtQuick 2.6\n"
"import \"..\"\n"
"Item { property int t: ValueSource.something }",
- QUrl::fromLocalFile(dataDirectory + "/abc/Xyz.qml"));
- QCOMPARE(component.status(), QQmlComponent::Ready);
+ testFileUrl("abc/Xyz.qml"));
+ QVERIFY2(component.status() == QQmlComponent::Ready, qPrintable(component.errorString()));
QScopedPointer<QObject> o(component.create());
QVERIFY(o.data());
QCOMPARE(o->property("t").toInt(), 10);
@@ -389,6 +395,9 @@ public:
void tst_QQMLTypeLoader::intercept()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("Loading dynamic plugins does not work on Android");
+#endif
qmlClearTypeRegistrations();
QQmlEngine engine;
@@ -478,6 +487,9 @@ static void checkCleanCacheLoad(const QString &testCase)
void tst_QQMLTypeLoader::multiSingletonModule()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("Android seems to have problems with QProcess");
+#endif
qmlClearTypeRegistrations();
QQmlEngine engine;
engine.addImportPath(testFile("imports"));
@@ -498,6 +510,9 @@ void tst_QQMLTypeLoader::multiSingletonModule()
void tst_QQMLTypeLoader::implicitComponentModule()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("Android seems to have problems with QProcess");
+#endif
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("implicitcomponent.qml"));
QCOMPARE(component.status(), QQmlComponent::Ready);
diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.pro b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.pro
index 0352561e03..743f7cf3ac 100644
--- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.pro
+++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.pro
@@ -12,3 +12,4 @@ HEADERS += \
include (../../shared/util.pri)
+TESTDATA = data/*
diff --git a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
index 83a37df797..8a602a0356 100644
--- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
+++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
@@ -784,6 +784,7 @@ void tst_qqmlvaluetypes::font()
{
QQmlComponent component(&engine, testFileUrl("font_read.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
QVERIFY(object != nullptr);
QCOMPARE(object->property("f_family").toString(), object->font().family());
@@ -793,8 +794,19 @@ void tst_qqmlvaluetypes::font()
QCOMPARE(object->property("f_underline").toBool(), object->font().underline());
QCOMPARE(object->property("f_overline").toBool(), object->font().overline());
QCOMPARE(object->property("f_strikeout").toBool(), object->font().strikeOut());
- QCOMPARE(object->property("f_pointSize").toDouble(), object->font().pointSizeF());
- QCOMPARE(object->property("f_pixelSize").toInt(), int((object->font().pointSizeF() * qt_defaultDpi()) / qreal(72.)));
+
+ // If QFont::pixelSize() was set, QFont::pointSizeF() would return -1.
+ // If QFont::pointSizeF() was set, QFont::pixelSize() would return -1.
+ // QQuickFontValueType doesn't follow this semantic (if its -1 it calculates the value of
+ // the property from the other one)
+ double expectedPointSizeF = object->font().pointSizeF();
+ if (expectedPointSizeF == -1) expectedPointSizeF = object->font().pixelSize() * qreal(72.) / qreal(qt_defaultDpi());
+ int expectedPixelSize = object->font().pixelSize();
+ if (expectedPixelSize == -1) expectedPixelSize = int((object->font().pointSizeF() * qt_defaultDpi()) / qreal(72.));
+
+ QCOMPARE(object->property("f_pointSize").toDouble(), expectedPointSizeF);
+ QCOMPARE(object->property("f_pixelSize").toInt(), expectedPixelSize);
+
QCOMPARE(object->property("f_capitalization").toInt(), (int)object->font().capitalization());
QCOMPARE(object->property("f_letterSpacing").toDouble(), object->font().letterSpacing());
QCOMPARE(object->property("f_wordSpacing").toDouble(), object->font().wordSpacing());
diff --git a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp
index 4b2ae45bae..b7600351b7 100644
--- a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp
+++ b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp
@@ -112,6 +112,10 @@ void tst_qquickfolderlistmodel::initTestCase()
void tst_qquickfolderlistmodel::basicProperties()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("[QTBUG-77335] Initial folder of FolderListModel on Android does not work properly,"
+ " and from there on it is unreliable to change the folder");
+#endif
QQmlComponent component(&engine, testFileUrl("basic.qml"));
checkNoErrors(component);
@@ -356,6 +360,9 @@ void tst_qquickfolderlistmodel::showDotAndDotDot()
void tst_qquickfolderlistmodel::showDotAndDotDot_data()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("Resource file system does not list '.' and '..' due to QDir::entryList() behavior");
+#endif
QTest::addColumn<QUrl>("folder");
QTest::addColumn<QUrl>("rootFolder");
QTest::addColumn<bool>("showDotAndDotDot");
@@ -411,7 +418,7 @@ void tst_qquickfolderlistmodel::sortCaseSensitive()
QAbstractListModel *flm = qobject_cast<QAbstractListModel*>(component.create());
QVERIFY(flm != 0);
- flm->setProperty("folder", QUrl::fromLocalFile(dataDirectoryUrl().path() + QLatin1String("/sortdir")));
+ flm->setProperty("folder", testFileUrl("sortdir"));
flm->setProperty("sortCaseSensitive", sortCaseSensitive);
QTRY_COMPARE(flm->property("count").toInt(), 2); // wait for refresh
for (int i = 0; i < 2; ++i)
diff --git a/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp b/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp
index 392ce16880..5dd8e9dcc0 100644
--- a/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp
+++ b/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp
@@ -59,7 +59,7 @@ void tst_QV4Assembler::initTestCase()
void tst_QV4Assembler::perfMapFile()
{
-#if !defined(Q_OS_LINUX)
+#if !defined(Q_OS_LINUX) || defined(Q_OS_ANDROID)
QSKIP("perf map files are only generated on linux");
#else
const QString qmljs = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmljs";
diff --git a/tests/auto/qml/qv4mm/tst_qv4mm.cpp b/tests/auto/qml/qv4mm/tst_qv4mm.cpp
index 1e34b79954..5d635aa63b 100644
--- a/tests/auto/qml/qv4mm/tst_qv4mm.cpp
+++ b/tests/auto/qml/qv4mm/tst_qv4mm.cpp
@@ -136,7 +136,7 @@ void tst_qv4mm::clearICParent()
// to change this test.
for (uint i = 0; i < 16 * 1024; ++i) {
QV4::Scope scope(&engine);
- QV4::ScopedString s(scope, identifiers->getIndexed(i));
+ QV4::ScopedString s(scope, identifiers->get(i));
QV4::Scoped<QV4::InternalClass> ic(scope, object->internalClass());
QVERIFY(ic->d()->parent != nullptr);
object->deleteProperty(s->toPropertyKey());
diff --git a/tests/auto/quick/qquickborderimage/data/multi.ico b/tests/auto/quick/qquickborderimage/data/multi.ico
new file mode 100644
index 0000000000..b748ceaa29
--- /dev/null
+++ b/tests/auto/quick/qquickborderimage/data/multi.ico
Binary files differ
diff --git a/tests/auto/quick/qquickborderimage/data/multiframe.qml b/tests/auto/quick/qquickborderimage/data/multiframe.qml
new file mode 100644
index 0000000000..8bd32da5a6
--- /dev/null
+++ b/tests/auto/quick/qquickborderimage/data/multiframe.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.14
+
+BorderImage {
+ source: "multi.ico"
+ border { left: 19; top: 19; right: 19; bottom: 19 }
+ width: 160; height: 160
+ horizontalTileMode: BorderImage.Stretch
+}
diff --git a/tests/auto/quick/qquickborderimage/data/multiframeAsync.qml b/tests/auto/quick/qquickborderimage/data/multiframeAsync.qml
new file mode 100644
index 0000000000..059e4becf3
--- /dev/null
+++ b/tests/auto/quick/qquickborderimage/data/multiframeAsync.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.14
+
+BorderImage {
+ source: "multi.ico"
+ asynchronous: true
+ border { left: 19; top: 19; right: 19; bottom: 19 }
+ width: 160; height: 160
+ horizontalTileMode: BorderImage.Stretch
+}
diff --git a/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp b/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp
index 9292e1886a..dc3a783600 100644
--- a/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp
+++ b/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp
@@ -46,6 +46,8 @@
#include "../../shared/util.h"
#include "../shared/visualtestutil.h"
+Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
+
Q_DECLARE_METATYPE(QQuickImageBase::Status)
class tst_qquickborderimage : public QQmlDataTest
@@ -79,6 +81,8 @@ private slots:
#if QT_CONFIG(opengl)
void borderImageMesh();
#endif
+ void multiFrame_data();
+ void multiFrame();
private:
QQmlEngine engine;
@@ -601,6 +605,67 @@ void tst_qquickborderimage::borderImageMesh()
qPrintable(errorMessage));
}
#endif
+
+void tst_qquickborderimage::multiFrame_data()
+{
+ QTest::addColumn<QString>("qmlfile");
+ QTest::addColumn<bool>("asynchronous");
+
+ QTest::addRow("default") << "multiframe.qml" << false;
+ QTest::addRow("async") << "multiframeAsync.qml" << true;
+}
+
+void tst_qquickborderimage::multiFrame()
+{
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms");
+
+ QFETCH(QString, qmlfile);
+ QFETCH(bool, asynchronous);
+ Q_UNUSED(asynchronous)
+
+ QQuickView view(testFileUrl(qmlfile));
+ QQuickBorderImage *image = qobject_cast<QQuickBorderImage*>(view.rootObject());
+ QVERIFY(image);
+ QSignalSpy countSpy(image, SIGNAL(frameCountChanged()));
+ QSignalSpy currentSpy(image, SIGNAL(currentFrameChanged()));
+ if (asynchronous) {
+ QCOMPARE(image->frameCount(), 0);
+ QTRY_COMPARE(image->frameCount(), 4);
+ QCOMPARE(countSpy.count(), 1);
+ } else {
+ QCOMPARE(image->frameCount(), 4);
+ }
+ QCOMPARE(image->currentFrame(), 0);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+ QCoreApplication::processEvents(); // Process all queued events
+
+ QImage contents = view.grabWindow();
+ if (contents.width() < 160)
+ QSKIP("Skipping due to grabWindow not functional");
+
+ // The middle of the first frame looks blue, approximately qRgba(0x43, 0x7e, 0xd6, 0xff)
+ QColor color = contents.pixelColor(60, 60);
+ qCDebug(lcTests) << "expected bluish color, got" << color;
+ QVERIFY(color.redF() < 0.75);
+ QVERIFY(color.greenF() < 0.75);
+ QVERIFY(color.blueF() > 0.75);
+
+ image->setCurrentFrame(1);
+ QTRY_COMPARE(image->status(), QQuickImageBase::Ready);
+ QCOMPARE(currentSpy.count(), 1);
+ QCOMPARE(image->currentFrame(), 1);
+ contents = view.grabWindow();
+ // The middle of the second frame looks green, approximately qRgba(0x3a, 0xd2, 0x31, 0xff)
+ color = contents.pixelColor(60, 60);
+ qCDebug(lcTests) << "expected greenish color, got" << color;
+ QVERIFY(color.redF() < 0.75);
+ QVERIFY(color.green() > 0.75);
+ QVERIFY(color.blueF() < 0.75);
+}
+
QTEST_MAIN(tst_qquickborderimage)
#include "tst_qquickborderimage.moc"
diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
index 2314b82e8c..c104eecbcd 100644
--- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
+++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
@@ -874,7 +874,8 @@ void tst_qquickflickable::wheel()
// test a vertical flick
{
QPoint pos(200, 200);
- QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(), QPoint(0,-120), -120, Qt::Vertical, Qt::NoButton, Qt::NoModifier);
+ QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(), QPoint(0,-120),
+ Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
event.setAccepted(false);
QGuiApplication::sendEvent(window.data(), &event);
}
@@ -897,7 +898,8 @@ void tst_qquickflickable::wheel()
// test a horizontal flick
{
QPoint pos(200, 200);
- QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(), QPoint(-120,0), -120, Qt::Horizontal, Qt::NoButton, Qt::NoModifier);
+ QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(), QPoint(-120,0),
+ Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
event.setAccepted(false);
QGuiApplication::sendEvent(window.data(), &event);
@@ -926,7 +928,8 @@ void tst_qquickflickable::trackpad()
QPoint pos(200, 200);
{
- QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(0,-100), QPoint(0,-120), -120, Qt::Vertical, Qt::NoButton, Qt::NoModifier, Qt::ScrollBegin);
+ QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(0,-100), QPoint(0,-120),
+ Qt::NoButton, Qt::NoModifier, Qt::ScrollBegin, false);
event.setAccepted(false);
QGuiApplication::sendEvent(window.data(), &event);
}
@@ -938,7 +941,8 @@ void tst_qquickflickable::trackpad()
QCOMPARE(flick->contentY(), qreal(0));
{
- QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(-100,0), QPoint(-120,0), -120, Qt::Horizontal, Qt::NoButton, Qt::NoModifier, Qt::ScrollUpdate);
+ QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(-100,0), QPoint(-120,0),
+ Qt::NoButton, Qt::NoModifier, Qt::ScrollUpdate, false);
event.setAccepted(false);
QGuiApplication::sendEvent(window.data(), &event);
}
@@ -947,7 +951,8 @@ void tst_qquickflickable::trackpad()
QCOMPARE(flick->contentY(), qreal(0));
{
- QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(0,0), QPoint(0,0), 0, Qt::Horizontal, Qt::NoButton, Qt::NoModifier, Qt::ScrollEnd);
+ QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(0,0), QPoint(0,0),
+ Qt::NoButton, Qt::NoModifier, Qt::ScrollEnd, false);
event.setAccepted(false);
QGuiApplication::sendEvent(window.data(), &event);
}
diff --git a/tests/auto/quick/qquickimage/data/multi.ico b/tests/auto/quick/qquickimage/data/multi.ico
new file mode 100644
index 0000000000..b748ceaa29
--- /dev/null
+++ b/tests/auto/quick/qquickimage/data/multi.ico
Binary files differ
diff --git a/tests/auto/quick/qquickimage/data/multiframe.qml b/tests/auto/quick/qquickimage/data/multiframe.qml
new file mode 100644
index 0000000000..df70bc784c
--- /dev/null
+++ b/tests/auto/quick/qquickimage/data/multiframe.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.14
+
+Image {
+ source: "multi.ico"
+}
diff --git a/tests/auto/quick/qquickimage/data/multiframeAsync.qml b/tests/auto/quick/qquickimage/data/multiframeAsync.qml
new file mode 100644
index 0000000000..167b4a3e57
--- /dev/null
+++ b/tests/auto/quick/qquickimage/data/multiframeAsync.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.14
+
+Image {
+ source: "multi.ico"
+ asynchronous: true
+}
diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
index 34c18aa64b..abc7cd86bd 100644
--- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp
+++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
@@ -97,6 +97,8 @@ private slots:
void highDpiFillModesAndSizes();
void hugeImages();
void urlInterceptor();
+ void multiFrame_data();
+ void multiFrame();
private:
QQmlEngine engine;
@@ -1132,6 +1134,62 @@ void tst_qquickimage::urlInterceptor()
QTRY_COMPARE(object->progress(), 1.0);
}
+void tst_qquickimage::multiFrame_data()
+{
+ QTest::addColumn<QString>("qmlfile");
+ QTest::addColumn<bool>("asynchronous");
+
+ QTest::addRow("default") << "multiframe.qml" << false;
+ QTest::addRow("async") << "multiframeAsync.qml" << true;
+}
+
+void tst_qquickimage::multiFrame()
+{
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms");
+
+ QFETCH(QString, qmlfile);
+ QFETCH(bool, asynchronous);
+ Q_UNUSED(asynchronous)
+
+ QQuickView view(testFileUrl(qmlfile));
+ QQuickImage *image = qobject_cast<QQuickImage*>(view.rootObject());
+ QVERIFY(image);
+ QSignalSpy countSpy(image, SIGNAL(frameCountChanged()));
+ QSignalSpy currentSpy(image, SIGNAL(currentFrameChanged()));
+ if (asynchronous) {
+ QCOMPARE(image->frameCount(), 0);
+ QTRY_COMPARE(image->frameCount(), 4);
+ QCOMPARE(countSpy.count(), 1);
+ } else {
+ QCOMPARE(image->frameCount(), 4);
+ }
+ QCOMPARE(image->currentFrame(), 0);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QImage contents = view.grabWindow();
+ if (contents.width() < 40)
+ QSKIP("Skipping due to grabWindow not functional");
+ // The first frame is a blue ball, approximately qRgba(0x33, 0x6d, 0xcc, 0xff)
+ QRgb color = contents.pixel(16, 16);
+ QVERIFY(qRed(color) < 0xc0);
+ QVERIFY(qGreen(color) < 0xc0);
+ QVERIFY(qBlue(color) > 0xc0);
+
+ image->setCurrentFrame(1);
+ QTRY_COMPARE(image->status(), QQuickImageBase::Ready);
+ QCOMPARE(currentSpy.count(), 1);
+ QCOMPARE(image->currentFrame(), 1);
+ contents = view.grabWindow();
+ // The second frame is a green ball, approximately qRgba(0x27, 0xc8, 0x22, 0xff)
+ color = contents.pixel(16, 16);
+ QVERIFY(qRed(color) < 0xc0);
+ QVERIFY(qGreen(color) > 0xc0);
+ QVERIFY(qBlue(color) < 0xc0);
+}
+
QTEST_MAIN(tst_qquickimage)
#include "tst_qquickimage.moc"
diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
index 7e132f97b6..b6e40d5117 100644
--- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
@@ -83,8 +83,8 @@ protected:
event->accept();
++wheelCount;
timestamp = event->timestamp();
- lastWheelEventPos = event->pos();
- lastWheelEventGlobalPos = event->globalPos();
+ lastWheelEventPos = event->position().toPoint();
+ lastWheelEventGlobalPos = event->globalPosition().toPoint();
}
};
@@ -1462,7 +1462,8 @@ void tst_qquickitem::wheelEvent()
QPoint localPoint(width / 2, height / 2);
QPoint globalPoint = window.mapToGlobal(localPoint);
- QWheelEvent event(localPoint, globalPoint, -120, Qt::NoButton, Qt::NoModifier, Qt::Vertical);
+ QWheelEvent event(localPoint, globalPoint, QPoint(0, 0), QPoint(0, -120),
+ Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
event.setTimestamp(123456UL);
event.setAccepted(false);
QGuiApplication::sendEvent(&window, &event);
diff --git a/tests/auto/quick/qquicklistview/data/addoncompleted.qml b/tests/auto/quick/qquicklistview/data/addoncompleted.qml
index 57265cb2c0..2341295868 100644
--- a/tests/auto/quick/qquicklistview/data/addoncompleted.qml
+++ b/tests/auto/quick/qquicklistview/data/addoncompleted.qml
@@ -73,6 +73,9 @@ Rectangle {
anchors.fill: parent
model: listModel
objectName: "view"
+ // buffered delegates are created asynchronously
+ // therefore we disable buffering
+ cacheBuffer: 0
delegate: Rectangle {
height: 15
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index bab2ec34f8..08149a1786 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -8958,6 +8958,7 @@ void tst_QQuickListView::addOnCompleted()
y = 9999999;
} else {
const qreal newY = item->y();
+ QVERIFY(newY != 9999999); // once we could not find an item, we shouldn' find any further ones
QVERIFY2(newY > y, objName.toUtf8().constData());
y = newY;
}
diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
index 4215017db3..5844720aa4 100644
--- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
+++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
@@ -1519,7 +1519,7 @@ void tst_QQuickMouseArea::onWheel()
QVERIFY(root != nullptr);
QWheelEvent wheelEvent(QPoint(10, 32), QPoint(10, 32), QPoint(60, 20), QPoint(0, 120),
- 0, Qt::Vertical,Qt::NoButton, Qt::ControlModifier);
+ Qt::NoButton, Qt::ControlModifier, Qt::NoScrollPhase, false);
QGuiApplication::sendEvent(&window, &wheelEvent);
QCOMPARE(root->property("angleDeltaY").toInt(), 120);
diff --git a/tests/auto/quick/qquickshape/data/multiline.png b/tests/auto/quick/qquickshape/data/multiline.png
new file mode 100644
index 0000000000..ae25d111df
--- /dev/null
+++ b/tests/auto/quick/qquickshape/data/multiline.png
Binary files differ
diff --git a/tests/auto/quick/qquickshape/data/multiline.qml b/tests/auto/quick/qquickshape/data/multiline.qml
new file mode 100644
index 0000000000..ad07506972
--- /dev/null
+++ b/tests/auto/quick/qquickshape/data/multiline.qml
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.14
+import QtQuick.Shapes 1.14
+
+Shape {
+ width: 200
+ height: 150
+ vendorExtensionsEnabled: false
+ objectName: "shape"
+ id: shape
+ property alias paths: multiline.paths
+ property point vertexBeingChecked;
+
+ function checkVertexAt(i, j) {
+ vertexBeingChecked = multiline.paths[i][j]
+ }
+
+ ShapePath {
+ strokeWidth: 4
+ strokeColor: "green"
+ PathMultiline {
+ id: multiline
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickshape/data/multilineStronglyTyped.qml b/tests/auto/quick/qquickshape/data/multilineStronglyTyped.qml
new file mode 100644
index 0000000000..46d650e053
--- /dev/null
+++ b/tests/auto/quick/qquickshape/data/multilineStronglyTyped.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.14
+import QtQuick.Shapes 1.14
+import Qt.test 1.0
+
+Shape {
+ width: 200
+ height: 150
+ vendorExtensionsEnabled: false
+ objectName: "shape"
+ id: shape
+ property alias paths: multiline.paths
+ property point vertexBeingChecked;
+
+ function checkVertexAt(i, j) {
+ vertexBeingChecked = multiline.paths[i][j]
+ }
+
+ PolygonProvider {
+ id: provider
+ objectName: "provider"
+ }
+
+ ShapePath {
+ strokeWidth: 4
+ strokeColor: "green"
+ PathMultiline {
+ id: multiline
+ paths: provider.paths
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickshape/data/polyline.png b/tests/auto/quick/qquickshape/data/polyline.png
new file mode 100644
index 0000000000..00123fba44
--- /dev/null
+++ b/tests/auto/quick/qquickshape/data/polyline.png
Binary files differ
diff --git a/tests/auto/quick/qquickshape/data/polyline.qml b/tests/auto/quick/qquickshape/data/polyline.qml
new file mode 100644
index 0000000000..e62d952ae7
--- /dev/null
+++ b/tests/auto/quick/qquickshape/data/polyline.qml
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.14
+import QtQuick.Shapes 1.14
+
+Shape {
+ width: 200
+ height: 150
+ vendorExtensionsEnabled: false
+ objectName: "shape"
+ id: shape
+ property alias path: polyline.path
+ property point vertexBeingChecked;
+
+ function checkVertexAt(i) {
+ vertexBeingChecked = polyline.path[i]
+ }
+
+ ShapePath {
+ strokeWidth: 4
+ strokeColor: "green"
+ PathPolyline {
+ id: polyline
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickshape/tst_qquickshape.cpp b/tests/auto/quick/qquickshape/tst_qquickshape.cpp
index b3b8d2d148..851475e2cd 100644
--- a/tests/auto/quick/qquickshape/tst_qquickshape.cpp
+++ b/tests/auto/quick/qquickshape/tst_qquickshape.cpp
@@ -43,6 +43,28 @@
using namespace QQuickViewTestUtil;
using namespace QQuickVisualTestUtil;
+class PolygonProvider : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QVector<QPolygonF> paths READ paths WRITE setPaths NOTIFY pathsChanged)
+
+public:
+ QVector<QPolygonF> paths() const { return m_paths; }
+ void setPaths(QVector<QPolygonF> paths)
+ {
+ if (m_paths == paths)
+ return;
+ m_paths = paths;
+ emit pathsChanged();
+ }
+
+signals:
+ void pathsChanged();
+
+private:
+ QVector<QPolygonF> m_paths;
+};
+
class tst_QQuickShape : public QQmlDataTest
{
Q_OBJECT
@@ -60,6 +82,14 @@ private slots:
void conicalGrad();
void renderPolyline();
void renderMultiline();
+ void polylineDataTypes_data();
+ void polylineDataTypes();
+ void multilineDataTypes_data();
+ void multilineDataTypes();
+ void multilineStronglyTyped();
+
+private:
+ QVector<QPolygonF> m_lowPolyLogo;
};
tst_QQuickShape::tst_QQuickShape()
@@ -75,6 +105,30 @@ tst_QQuickShape::tst_QQuickShape()
qmlRegisterType<QQuickShapeRadialGradient>(uri, 1, 0, "RadialGradient");
qmlRegisterType<QQuickShapeConicalGradient>(uri, 1, 0, "ConicalGradient");
qmlRegisterType<QQuickPathPolyline>(uri, 1, 0, "PathPolyline");
+ qmlRegisterType<PolygonProvider>("Qt.test", 1, 0, "PolygonProvider");
+
+ m_lowPolyLogo << (QPolygonF() <<
+ QPointF(20, 0) <<
+ QPointF(140, 0) <<
+ QPointF(140, 80) <<
+ QPointF(120, 100) <<
+ QPointF(0, 100) <<
+ QPointF(0, 20) <<
+ QPointF(20, 0) )
+ << (QPolygonF() << QPointF(20, 80) <<
+ QPointF(60, 80) <<
+ QPointF(80, 60) <<
+ QPointF(80, 20) <<
+ QPointF(40, 20) <<
+ QPointF(20, 40) <<
+ QPointF(20, 80) )
+ << (QPolygonF() << QPointF(80, 80) <<
+ QPointF(70, 70) )
+ << (QPolygonF() << QPointF(120, 80) <<
+ QPointF(100, 60) <<
+ QPointF(100, 20) )
+ << (QPolygonF() << QPointF(100, 40) <<
+ QPointF(120, 40) );
}
void tst_QQuickShape::initValues()
@@ -373,6 +427,286 @@ void tst_QQuickShape::renderMultiline()
QVERIFY2(res, qPrintable(errorMessage));
}
+void tst_QQuickShape::polylineDataTypes_data()
+{
+ QTest::addColumn<QVariant>("path");
+
+ QTest::newRow("polygon") << QVariant::fromValue(m_lowPolyLogo.first());
+ {
+ QVector<QPointF> points;
+ points << m_lowPolyLogo.first();
+ QTest::newRow("vector of points") << QVariant::fromValue(points);
+ }
+ {
+ QList<QPointF> points;
+ for (const auto &point : m_lowPolyLogo.first())
+ points << point;
+ QTest::newRow("list of points") << QVariant::fromValue(points);
+ }
+ {
+ QVariantList points;
+ for (const auto &point : m_lowPolyLogo.first())
+ points << point;
+ QTest::newRow("QVariantList of points") << QVariant::fromValue(points);
+ }
+ {
+ QVector<QPoint> points;
+ for (const auto &point : m_lowPolyLogo.first())
+ points << point.toPoint();
+ QTest::newRow("vector of QPoint (integer points)") << QVariant::fromValue(points);
+ }
+ // Oddly, QPolygon is not supported, even though it's really QVector<QPoint>.
+ // We don't want to have a special case for it in QQuickPathPolyline::setPath(),
+ // but it could potentially be supported by fixing one of the QVariant conversions.
+}
+
+void tst_QQuickShape::polylineDataTypes()
+{
+ QFETCH(QVariant, path);
+
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("polyline.qml"));
+ QQuickShape *shape = qobject_cast<QQuickShape *>(window->rootObject());
+ QVERIFY(shape);
+ shape->setProperty("path", path);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimimal platforms", Abort);
+
+ QImage img = window->grabWindow();
+ QVERIFY(!img.isNull());
+
+ QImage refImg(testFileUrl("polyline.png").toLocalFile());
+ QVERIFY(!refImg.isNull());
+
+ QString errorMessage;
+ const QImage actualImg = img.convertToFormat(refImg.format());
+ const bool res = QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage);
+ if (!res) { // For visual inspection purposes.
+ QTest::qWait(5000);
+ const QString &tempLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
+ actualImg.save(tempLocation + QLatin1String("/polyline.png"));
+ }
+ QVERIFY2(res, qPrintable(errorMessage));
+
+ QCOMPARE(shape->property("path").value<QVector<QPointF>>(), m_lowPolyLogo.first());
+ // Verify that QML sees it as an array of points
+ int i = 0;
+ for (QPointF p : m_lowPolyLogo.first()) {
+ QMetaObject::invokeMethod(shape, "checkVertexAt", Q_ARG(QVariant, QVariant::fromValue<int>(i++)));
+ QCOMPARE(shape->property("vertexBeingChecked").toPointF(), p);
+ }
+}
+
+void tst_QQuickShape::multilineDataTypes_data()
+{
+ QTest::addColumn<QVariant>("paths");
+
+ QTest::newRow("vector of polygons") << QVariant::fromValue(m_lowPolyLogo);
+ {
+ QVector<QVector<QPointF>> paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QVector<QPointF> points;
+ points << poly;
+ paths << points;
+ }
+ QTest::newRow("vector of point vectors") << QVariant::fromValue(paths);
+ }
+ {
+ QList<QVector<QPointF>> paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QVector<QPointF> points;
+ points << poly;
+ paths << points;
+ }
+ QTest::newRow("list of point vectors") << QVariant::fromValue(paths);
+ }
+ {
+ QList<QList<QPointF>> paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QList<QPointF> points;
+ for (const auto &point : poly)
+ points << point;
+ paths << points;
+ }
+ QTest::newRow("list of point lists") << QVariant::fromValue(paths);
+ }
+ {
+ QVariantList paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QVector<QPointF> points;
+ points << poly;
+ paths << QVariant::fromValue(points);
+ }
+ QTest::newRow("QVariantList of point vectors") << QVariant::fromValue(paths);
+ }
+ {
+ QVariantList paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QList<QPointF> points;
+ for (const auto &point : poly)
+ points << point;
+ paths << QVariant::fromValue(points);
+ }
+ QTest::newRow("QVariantList of point lists") << QVariant::fromValue(paths);
+ }
+ {
+ QVariantList paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QVariantList points;
+ for (const auto &point : poly)
+ points << point;
+ paths << QVariant::fromValue(points);
+ }
+ QTest::newRow("QVariantList of QVariantLists") << QVariant::fromValue(paths);
+ }
+ /* These could be supported if QVariant knew how to convert lists and vectors of QPolygon to QPolygonF.
+ But they are omitted for now because we don't want to have special cases for them
+ in QQuickPathMultiline::setPaths(). Floating point is preferred for geometry in Qt Quick.
+ {
+ QList<QPolygon> paths;
+ for (const auto &poly : m_lowPolyLogo)
+ paths << poly.toPolygon();
+ QTest::newRow("list of QPolygon (integer points)") << QVariant::fromValue(paths);
+ }
+ {
+ QVector<QPolygon> paths;
+ for (const auto &poly : m_lowPolyLogo)
+ paths << poly.toPolygon();
+ QTest::newRow("vector of QPolygon (integer points)") << QVariant::fromValue(paths);
+ }
+ */
+ {
+ QList<QList<QPoint>> paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QList<QPoint> points;
+ for (const auto &point : poly)
+ points << point.toPoint();
+ paths << points;
+ }
+ QTest::newRow("list of integer point lists") << QVariant::fromValue(paths);
+ }
+ {
+ QVector<QList<QPoint>> paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QList<QPoint> points;
+ for (const auto &point : poly)
+ points << point.toPoint();
+ paths << points;
+ }
+ QTest::newRow("vector of integer point lists") << QVariant::fromValue(paths);
+ }
+ {
+ QList<QVector<QPoint>> paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QVector<QPoint> points;
+ for (const auto &point : poly)
+ points << point.toPoint();
+ paths << points;
+ }
+ QTest::newRow("list of integer point vectors") << QVariant::fromValue(paths);
+ }
+}
+
+void tst_QQuickShape::multilineDataTypes()
+{
+ QFETCH(QVariant, paths);
+
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("multiline.qml"));
+ QQuickShape *shape = qobject_cast<QQuickShape *>(window->rootObject());
+ QVERIFY(shape);
+ shape->setProperty("paths", paths);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimimal platforms", Abort);
+
+ QImage img = window->grabWindow();
+ QVERIFY(!img.isNull());
+
+ QImage refImg(testFileUrl("multiline.png").toLocalFile());
+ QVERIFY(!refImg.isNull());
+
+ QString errorMessage;
+ const QImage actualImg = img.convertToFormat(refImg.format());
+ const bool res = QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage);
+ if (!res) { // For visual inspection purposes.
+ QTest::qWait(5000);
+ const QString &tempLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
+ actualImg.save(tempLocation + QLatin1String("/multiline.png"));
+ }
+ QVERIFY2(res, qPrintable(errorMessage));
+
+ QVector<QVector<QPointF>> pointVectors;
+ for (auto v : m_lowPolyLogo)
+ pointVectors << v;
+ QCOMPARE(shape->property("paths").value<QVector<QVector<QPointF>>>(), pointVectors);
+ // Verify that QML sees it as an array of arrays of points
+ int i = 0;
+ for (auto pv : m_lowPolyLogo) {
+ int j = 0;
+ for (QPointF p : pv) {
+ QMetaObject::invokeMethod(shape, "checkVertexAt", Q_ARG(QVariant, QVariant::fromValue<int>(i)), Q_ARG(QVariant, QVariant::fromValue<int>(j++)));
+ QCOMPARE(shape->property("vertexBeingChecked").toPointF(), p);
+ }
+ ++i;
+ }
+}
+
+void tst_QQuickShape::multilineStronglyTyped()
+{
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("multilineStronglyTyped.qml"));
+ QQuickShape *shape = qobject_cast<QQuickShape *>(window->rootObject());
+ QVERIFY(shape);
+ PolygonProvider *provider = shape->findChild<PolygonProvider*>("provider");
+ QVERIFY(provider);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+ provider->setPaths(m_lowPolyLogo);
+
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimimal platforms", Abort);
+
+ QImage img = window->grabWindow();
+ QVERIFY(!img.isNull());
+
+ QImage refImg(testFileUrl("multiline.png").toLocalFile());
+ QVERIFY(!refImg.isNull());
+
+ QString errorMessage;
+ const QImage actualImg = img.convertToFormat(refImg.format());
+ const bool res = QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage);
+ if (!res) { // For visual inspection purposes.
+ QTest::qWait(5000);
+ const QString &tempLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
+ actualImg.save(tempLocation + QLatin1String("/multilineStronglyTyped.png"));
+ }
+ QVERIFY2(res, qPrintable(errorMessage));
+
+ QVector<QVector<QPointF>> pointVectors;
+ for (auto v : m_lowPolyLogo)
+ pointVectors << v;
+ QCOMPARE(shape->property("paths").value<QVector<QVector<QPointF>>>(), pointVectors);
+ // Verify that QML sees it as an array of arrays of points
+ int i = 0;
+ for (auto pv : m_lowPolyLogo) {
+ int j = 0;
+ for (QPointF p : pv) {
+ QMetaObject::invokeMethod(shape, "checkVertexAt", Q_ARG(QVariant, QVariant::fromValue<int>(i)), Q_ARG(QVariant, QVariant::fromValue<int>(j++)));
+ QCOMPARE(shape->property("vertexBeingChecked").toPointF(), p);
+ }
+ ++i;
+ }
+}
+
QTEST_MAIN(tst_QQuickShape)
#include "tst_qquickshape.moc"
diff --git a/tests/auto/quick/qquicktext/data/verticallyAlignedImageInTable.qml b/tests/auto/quick/qquicktext/data/verticallyAlignedImageInTable.qml
new file mode 100644
index 0000000000..4c00362d15
--- /dev/null
+++ b/tests/auto/quick/qquicktext/data/verticallyAlignedImageInTable.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+Item {
+ width: 320
+ height: 480
+
+ Text {
+ anchors.centerIn: parent
+ font.family: "Arial"
+ font.pixelSize: 16
+ textFormat: Text.RichText
+ text: "<table><tr><td/><td valign=\"top\"><img src=\"images/face-sad.png\"></td></tr></table>"
+ }
+}
diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
index fd0ba0f49b..97107694bd 100644
--- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp
+++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
@@ -162,6 +162,8 @@ private slots:
void initialContentHeight();
+ void verticallyAlignedImageInTable();
+
private:
QStringList standard;
QStringList richText;
@@ -4415,6 +4417,18 @@ void tst_qquicktext::implicitSizeChangeRewrap()
QVERIFY(text->contentWidth() < window->width());
}
+void tst_qquicktext::verticallyAlignedImageInTable()
+{
+ QScopedPointer<QQuickView> window(new QQuickView);
+ window->setSource(testFileUrl("verticallyAlignedImageInTable.qml"));
+ QTRY_COMPARE(window->status(), QQuickView::Ready);
+
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ // Don't crash
+}
+
QTEST_MAIN(tst_qquicktext)
#include "tst_qquicktext.moc"
diff --git a/tests/auto/quick/qquicktextedit/BLACKLIST b/tests/auto/quick/qquicktextedit/BLACKLIST
new file mode 100644
index 0000000000..9df9c7d75a
--- /dev/null
+++ b/tests/auto/quick/qquicktextedit/BLACKLIST
@@ -0,0 +1,2 @@
+[mouseSelection]
+opensuse-leap
diff --git a/tests/auto/quick/qquickview/tst_qquickview.cpp b/tests/auto/quick/qquickview/tst_qquickview.cpp
index e259ed1ae7..dbce0d308c 100644
--- a/tests/auto/quick/qquickview/tst_qquickview.cpp
+++ b/tests/auto/quick/qquickview/tst_qquickview.cpp
@@ -49,6 +49,7 @@ private slots:
void errors();
void engine();
void findChild();
+ void setInitialProperties();
};
@@ -283,6 +284,17 @@ void tst_QQuickView::findChild()
QVERIFY(!view.rootObject()->findChild<QObject *>("rootObject")); // self
}
+void tst_QQuickView::setInitialProperties()
+{
+ QQuickView view;
+ view.setInitialProperties({{"z", 4}, {"width", 100}});
+ view.setSource(testFileUrl("resizemodeitem.qml"));
+ QObject *rootObject = view.rootObject();
+ QVERIFY(rootObject);
+ QCOMPARE(rootObject->property("z").toInt(), 4);
+ QCOMPARE(rootObject->property("width").toInt(), 100);
+}
+
QTEST_MAIN(tst_QQuickView)
#include "tst_qquickview.moc"
diff --git a/tests/auto/shared/testhttpserver.cpp b/tests/auto/shared/testhttpserver.cpp
index 09f16e8635..f0d5a89984 100644
--- a/tests/auto/shared/testhttpserver.cpp
+++ b/tests/auto/shared/testhttpserver.cpp
@@ -32,6 +32,7 @@
#include <QFile>
#include <QTimer>
#include <QTest>
+#include <QQmlFile>
/*!
\internal
@@ -152,17 +153,17 @@ bool TestHTTPServer::wait(const QUrl &expect, const QUrl &reply, const QUrl &bod
m_state = AwaitingHeader;
m_data.clear();
- QFile expectFile(expect.toLocalFile());
+ QFile expectFile(QQmlFile::urlToLocalFileOrQrc(expect));
if (!expectFile.open(QIODevice::ReadOnly))
return false;
- QFile replyFile(reply.toLocalFile());
+ QFile replyFile(QQmlFile::urlToLocalFileOrQrc(reply));
if (!replyFile.open(QIODevice::ReadOnly))
return false;
m_bodyData = QByteArray();
if (body.isValid()) {
- QFile bodyFile(body.toLocalFile());
+ QFile bodyFile(QQmlFile::urlToLocalFileOrQrc(body));
if (!bodyFile.open(QIODevice::ReadOnly))
return false;
m_bodyData = bodyFile.readAll();
diff --git a/tests/benchmarks/qml/js/qjsengine/tst_qjsengine.cpp b/tests/benchmarks/qml/js/qjsengine/tst_qjsengine.cpp
index d13751385c..cb23d6edbd 100644
--- a/tests/benchmarks/qml/js/qjsengine/tst_qjsengine.cpp
+++ b/tests/benchmarks/qml/js/qjsengine/tst_qjsengine.cpp
@@ -452,7 +452,7 @@ void tst_QJSEngine::installTranslatorFunctions()
{
newEngine();
QBENCHMARK {
- m_engine->installTranslatorFunctions();
+ m_engine->installExtensions(QJSEngine::TranslationExtension);
}
}
@@ -471,7 +471,7 @@ void tst_QJSEngine::translation()
QFETCH(QString, text);
QFETCH(QString, fileName);
newEngine();
- m_engine->installTranslatorFunctions();
+ m_engine->installExtensions(QJSEngine::TranslationExtension);
QBENCHMARK {
(void)m_engine->evaluate(text, fileName);
diff --git a/tests/benchmarks/qml/painting/paintbenchmark.cpp b/tests/benchmarks/qml/painting/paintbenchmark.cpp
index d195675ab8..1500f39c9a 100644
--- a/tests/benchmarks/qml/painting/paintbenchmark.cpp
+++ b/tests/benchmarks/qml/painting/paintbenchmark.cpp
@@ -34,7 +34,7 @@
#include <QGLWidget>
#include <QTextLayout>
#include <QVBoxLayout>
-#include <QTime>
+#include <QElapsedTimer>
#include <QDebug>
#include <QRandomGenerator>
#include <QStaticText>
@@ -328,20 +328,20 @@ public:
}
void paintEvent(QPaintEvent *) {
- static int last = 0;
+ static qint64 last = 0;
static bool firstRun = true;
if (firstRun) {
timer.start();
firstRun = false;
} else {
- int elapsed = timer.elapsed();
+ qint64 elapsed = timer.elapsed();
qDebug() << "frame elapsed:" << elapsed - last;
last = elapsed;
}
QPainter p(this);
p.fillRect(rect(), Qt::white);
p.setPen(Qt::black);
- QTime drawTimer;
+ QElapsedTimer drawTimer;
drawTimer.start();
testFunc(p);
qDebug() << "draw time" << drawTimer.elapsed();
@@ -351,7 +351,7 @@ public:
qApp->quit();
}
- QTime timer;
+ QElapsedTimer timer;
int frames;
};
diff --git a/tests/manual/scenegraph_lancelot/data/text/text_table_vertically_aligned_image.qml b/tests/manual/scenegraph_lancelot/data/text/text_table_vertically_aligned_image.qml
new file mode 100644
index 0000000000..d712f94572
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/text/text_table_vertically_aligned_image.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+Item {
+ width: 320
+ height: 480
+
+ Text {
+ anchors.centerIn: parent
+ font.family: "Arial"
+ font.pixelSize: 16
+ textFormat: Text.RichText
+ text: "<table><tr><td/><td valign=\"top\"><img src=\"data/logo.png\"></td></tr></table>"
+ }
+}
diff --git a/tools/qmlcachegen/generateloader.cpp b/tools/qmlcachegen/generateloader.cpp
index 74208a25e2..1c8a5a016a 100644
--- a/tools/qmlcachegen/generateloader.cpp
+++ b/tools/qmlcachegen/generateloader.cpp
@@ -434,7 +434,11 @@ bool generateLoader(const QStringList &compiledFiles, const QStringList &sortedR
}
}
+#if QT_CONFIG(temporaryfile)
QSaveFile f(outputFileName);
+#else
+ QFile f(outputFileName);
+#endif
if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
*errorString = f.errorString();
return false;
@@ -445,10 +449,12 @@ bool generateLoader(const QStringList &compiledFiles, const QStringList &sortedR
return false;
}
+#if QT_CONFIG(temporaryfile)
if (!f.commit()) {
*errorString = f.errorString();
return false;
}
+#endif
return true;
}
diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp
index 0202bd4df0..9468d64839 100644
--- a/tools/qmlcachegen/qmlcachegen.cpp
+++ b/tools/qmlcachegen/qmlcachegen.cpp
@@ -334,7 +334,11 @@ static bool saveUnitAsCpp(const QString &inputFileName, const QString &outputFil
const QV4::CompiledData::SaveableUnitPointer &unit,
QString *errorString)
{
+#if QT_CONFIG(temporaryfile)
QSaveFile f(outputFileName);
+#else
+ QFile f(outputFileName);
+#endif
if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
*errorString = f.errorString();
return false;
@@ -392,10 +396,12 @@ static bool saveUnitAsCpp(const QString &inputFileName, const QString &outputFil
if (!writeStr("};\n}\n}\n"))
return false;
+#if QT_CONFIG(temporaryfile)
if (!f.commit()) {
*errorString = f.errorString();
return false;
}
+#endif
return true;
}
diff --git a/tools/qmlcachegen/qtquickcompiler.prf b/tools/qmlcachegen/qtquickcompiler.prf
index 24cbe7f2e5..2f98aadefe 100644
--- a/tools/qmlcachegen/qtquickcompiler.prf
+++ b/tools/qmlcachegen/qtquickcompiler.prf
@@ -1,15 +1,5 @@
if(qtc_run|lupdate_run): return()
-!contains(QT, qml) {
- qt_modules = \
- $$replace(QT, -private$, _private) \
- $$replace(QT_PRIVATE, -private$, _private)
- qt_modules = $$resolve_depends(qt_modules, "QT.", ".depends" ".run_depends")
- !contains(qt_modules, qml): \
- error("The qtquickcompiler feature cannot be used without the QML module.")
- unset(qt_modules)
-}
-
qtPrepareTool(QML_CACHEGEN, qmlcachegen, _FILTER)
qtPrepareTool(QMAKE_RCC, rcc, _DEP)
diff --git a/tools/qmlimportscanner/Qt5QmlImportScannerConfig.cmake.in b/tools/qmlimportscanner/Qt5QmlImportScannerConfig.cmake.in
new file mode 100644
index 0000000000..6cdfaf8f6f
--- /dev/null
+++ b/tools/qmlimportscanner/Qt5QmlImportScannerConfig.cmake.in
@@ -0,0 +1,184 @@
+include(CMakeParseArguments)
+
+function(QT5_IMPORT_QML_PLUGINS target)
+!!IF !isEmpty(CMAKE_STATIC_TYPE)
+ set(options)
+ set(oneValueArgs \"PATH_TO_SCAN\")
+ set(multiValueArgs)
+
+ cmake_parse_arguments(arg \"${options}\" \"${oneValueArgs}\" \"${multiValueArgs}\" ${ARGN})
+ if(NOT arg_PATH_TO_SCAN)
+ set(arg_PATH_TO_SCAN \"${CMAKE_CURRENT_SOURCE_DIR}\")
+ endif()
+
+ # Find location of qmlimportscanner.
+ find_package(Qt5 COMPONENTS Core)
+!!IF isEmpty(CMAKE_BIN_DIR_IS_ABSOLUTE)
+ set(tool_path
+ \"${_qt5Core_install_prefix}/$${CMAKE_BIN_DIR}qmlimportscanner$$CMAKE_BIN_SUFFIX\")
+!!ELSE
+ set(tool_path \"$${CMAKE_BIN_DIR}qmlimportscanner$$CMAKE_BIN_SUFFIX\")
+!!ENDIF
+ if(NOT EXISTS \"${tool_path}\" )
+ message(FATAL_ERROR \"The package \\\"Qt5QmlImportScannerConfig\\\" references the file
+ \\\"${tool_path}\\\"
+but this file does not exist. Possible reasons include:
+* The file was deleted, renamed, or moved to another location.
+* An install or uninstall procedure did not complete successfully.
+* The installation package was faulty.
+\")
+ endif()
+
+ # Find location of qml dir.
+!!IF isEmpty(CMAKE_QML_DIR_IS_ABSOLUTE)
+ set(qml_path \"${_qt5Core_install_prefix}/$${CMAKE_QML_DIR}\")
+!!ELSE
+ set(qml_path \"$${CMAKE_QML_DIR}\")
+!!ENDIF
+
+ # Small macro to avoid duplicating code in two different loops.
+ macro(_qt5_QmlImportScanner_parse_entry)
+ set(entry_name \"qml_import_scanner_import_${idx}\")
+ cmake_parse_arguments(\"entry\"
+ \"\"
+ \"CLASSNAME;NAME;PATH;PLUGIN;RELATIVEPATH;TYPE;VERSION;\" \"\"
+ ${${entry_name}})
+ endmacro()
+
+ # Macro used to populate the dependency link flags for a certain configuriation (debug vs
+ # release) of a plugin.
+ macro(_qt5_link_to_QmlImportScanner_library_dependencies Plugin Configuration PluginLocation
+ IsDebugAndRelease)
+
+ set_property(TARGET \"${Plugin}\" APPEND PROPERTY IMPORTED_CONFIGURATIONS ${Configuration})
+ set(_imported_location \"${PluginLocation}\")
+ _qt5_Core_check_file_exists(\"${_imported_location}\")
+ set_target_properties(\"${Plugin}\" PROPERTIES
+ \"IMPORTED_LOCATION_${Configuration}\" \"${_imported_location}\"
+ )
+
+ set(_static_deps
+ ${_Qt5${entry_PLUGIN}_STATIC_${Configuration}_LIB_DEPENDENCIES}
+ )
+
+ if(NOT "${IsDebugAndRelease}")
+ set(_genex_condition \"1\")
+ else()
+ if("${Configuration}" STREQUAL "DEBUG")
+ set(_genex_condition \"$<CONFIG:Debug>\")
+ else()
+ set(_genex_condition \"$<NOT:$<CONFIG:Debug>>\")
+ endif()
+ endif()
+ if(_static_deps)
+ set(_static_deps_genex \"$<${_genex_condition}:${_static_deps}>\")
+ target_link_libraries(${imported_target} INTERFACE \"${_static_deps_genex}\")
+ endif()
+
+ set(_static_link_flags \"${_Qt5${entry_PLUGIN}_STATIC_${Configuration}_LINK_FLAGS}\")
+ if(NOT CMAKE_VERSION VERSION_LESS \"3.13\" AND _static_link_flags)
+ set(_static_link_flags_genex \"$<${_genex_condition}:${_static_link_flags}>\")
+ target_link_options(${imported_target} INTERFACE \"${_static_link_flags_genex}\")
+ endif()
+ endmacro()
+
+ # Run qmlimportscanner and include the generated cmake file.
+ set(qml_imports_file_path
+ \"${CMAKE_CURRENT_BINARY_DIR}/Qt5_QmlPlugins_Imports_${target}.cmake\")
+
+ message(STATUS \"Running qmlimportscanner to find used QML plugins. \")
+ execute_process(COMMAND
+ \"${tool_path}\" \"${arg_PATH_TO_SCAN}\" -importPath \"${qml_path}\"
+ -cmake-output
+ OUTPUT_FILE \"${qml_imports_file_path}\")
+
+ include(\"${qml_imports_file_path}\" OPTIONAL RESULT_VARIABLE qml_imports_file_path_found)
+ if(NOT qml_imports_file_path_found)
+ message(FATAL_ERROR \"Could not find ${qml_imports_file_path} which was supposed to be generated by qmlimportscanner.\")
+ endif()
+
+ # Parse the generate cmake file.
+ # It is possible for the scanner to find no usage of QML, in which case the import count is 0.
+ if(qml_import_scanner_imports_count)
+ set(added_plugins \"\")
+ foreach(idx RANGE \"${qml_import_scanner_imports_count}\")
+ _qt5_QmlImportScanner_parse_entry()
+ if(entry_PATH AND entry_PLUGIN)
+ # Sometimes a plugin appears multiple times with different versions.
+ # Make sure to process it only once.
+ list(FIND added_plugins \"${entry_PLUGIN}\" _index)
+ if(NOT _index EQUAL -1)
+ continue()
+ endif()
+ list(APPEND added_plugins \"${entry_PLUGIN}\")
+
+ # Add an imported target that will contain the link libraries and link options read
+ # from one plugin prl file. This target will point to the actual plugin and contain
+ # static dependency libraries and link flags.
+ # By creating a target for each qml plugin, CMake will take care of link flag
+ # deduplication.
+ set(imported_target \"${target}_QmlImport_${entry_PLUGIN}\")
+ add_library(\"${imported_target}\" MODULE IMPORTED)
+ target_link_libraries(\"${target}\" PRIVATE \"${imported_target}\")
+
+ # Read static library dependencies from the plugin .prl file.
+ # And then set the link flags to the library dependencies extracted from the .prl
+ # file.
+!!IF !isEmpty(CMAKE_RELEASE_TYPE)
+ _qt5_Core_process_prl_file(
+ \"${entry_PATH}/$$QMAKE_PREFIX_STATICLIB${entry_PLUGIN}$${CMAKE_QML_PLUGIN_SUFFIX_RELEASE}.prl\" RELEASE
+ _Qt5${entry_PLUGIN}_STATIC_RELEASE_LIB_DEPENDENCIES
+ _Qt5${entry_PLUGIN}_STATIC_RELEASE_LINK_FLAGS
+ )
+ _qt5_link_to_QmlImportScanner_library_dependencies(
+ \"${imported_target}\"
+ RELEASE
+ \"${entry_PATH}/$$QMAKE_PREFIX_STATICLIB${entry_PLUGIN}$${CMAKE_QML_PLUGIN_SUFFIX_RELEASE}.$$QMAKE_EXTENSION_STATICLIB\"
+ $${CMAKE_DEBUG_AND_RELEASE})
+!!ENDIF
+
+!!IF !isEmpty(CMAKE_DEBUG_TYPE)
+ _qt5_Core_process_prl_file(
+ \"${entry_PATH}/$$QMAKE_PREFIX_STATICLIB${entry_PLUGIN}$${CMAKE_QML_PLUGIN_SUFFIX_DEBUG}.prl\" DEBUG
+ _Qt5${entry_PLUGIN}_STATIC_DEBUG_LIB_DEPENDENCIES
+ _Qt5${entry_PLUGIN}_STATIC_DEBUG_LINK_FLAGS
+ )
+ _qt5_link_to_QmlImportScanner_library_dependencies(
+ \"${imported_target}\"
+ DEBUG
+ \"${entry_PATH}/$$QMAKE_PREFIX_STATICLIB${entry_PLUGIN}$${CMAKE_QML_PLUGIN_SUFFIX_DEBUG}.$$QMAKE_EXTENSION_STATICLIB\"
+ $${CMAKE_DEBUG_AND_RELEASE})
+!!ENDIF
+ endif()
+ endforeach()
+
+ # Generate content for plugin initialization cpp file.
+ set(added_imports \"\")
+ set(qt5_qml_import_cpp_file_content \"\")
+ foreach(idx RANGE \"${qml_import_scanner_imports_count}\")
+ _qt5_QmlImportScanner_parse_entry()
+ if(entry_PLUGIN)
+ if(entry_CLASSNAME)
+ list(FIND added_imports \"${entry_PLUGIN}\" _index)
+ if(_index EQUAL -1)
+ string(APPEND qt5_qml_import_cpp_file_content
+ \"Q_IMPORT_PLUGIN(${entry_CLASSNAME})\n\")
+ list(APPEND added_imports \"${entry_PLUGIN}\")
+ endif()
+ else()
+ message(FATAL_ERROR
+ \"Plugin ${entry_PLUGIN} is missing a classname entry, please add one to the qmldir file.\")
+ endif()
+ endif()
+ endforeach()
+
+ # Write to the generated file, and include it as a source for the given target.
+ set(generated_import_cpp_path
+ \"${CMAKE_CURRENT_BINARY_DIR}/Qt5_QmlPlugins_Imports_${target}.cpp\")
+ configure_file(\"${Qt5QmlImportScanner_DIR}/Qt5QmlImportScannerTemplate.cpp.in\"
+ \"${generated_import_cpp_path}\"
+ @ONLY)
+ target_sources(${target} PRIVATE \"${generated_import_cpp_path}\")
+ endif()
+!!ENDIF // !isEmpty(CMAKE_STATIC_TYPE)
+endfunction()
diff --git a/tools/qmlimportscanner/Qt5QmlImportScannerTemplate.cpp.in b/tools/qmlimportscanner/Qt5QmlImportScannerTemplate.cpp.in
new file mode 100644
index 0000000000..4ed747a555
--- /dev/null
+++ b/tools/qmlimportscanner/Qt5QmlImportScannerTemplate.cpp.in
@@ -0,0 +1,5 @@
+// This file is autogenerated by CMake. It imports static plugin classes for
+// static plugins used by QML imports.
+#include <QtPlugin>
+
+@qt5_qml_import_cpp_file_content@
diff --git a/tools/qmlimportscanner/main.cpp b/tools/qmlimportscanner/main.cpp
index 05d1f7fdc0..6d48f6203d 100644
--- a/tools/qmlimportscanner/main.cpp
+++ b/tools/qmlimportscanner/main.cpp
@@ -496,6 +496,36 @@ QVariantList findQmlImportsRecursively(const QStringList &qmlDirs, const QString
return ret;
}
+
+QString generateCmakeIncludeFileContent(const QVariantList &importList) {
+ // The function assumes that "list" is a QVariantList with 0 or more QVariantMaps, where
+ // each map contains QString -> QVariant<QString> mappings. This matches with the structure
+ // that qmake parses for static qml plugin auto imporitng.
+ // So: [ {"a": "a","b": "b"}, {"c": "c"} ]
+ QString content;
+ QTextStream s(&content);
+ int importsCount = 0;
+ for (const QVariant &importVariant: importList) {
+ if (static_cast<QMetaType::Type>(importVariant.type()) == QMetaType::QVariantMap) {
+ s << QStringLiteral("set(qml_import_scanner_import_") << importsCount
+ << QStringLiteral(" \"");
+
+ const QMap<QString, QVariant> &importDict = importVariant.toMap();
+ for (auto it = importDict.cbegin(); it != importDict.cend(); ++it) {
+ s << it.key().toUpper() << QLatin1Char(';')
+ << it.value().toString() << QLatin1Char(';');
+ }
+ s << QStringLiteral("\")\n");
+ ++importsCount;
+ }
+ }
+ if (importsCount >= 0) {
+ content.prepend(QString(QStringLiteral("set(qml_import_scanner_imports_count %1)\n"))
+ .arg(importsCount));
+ }
+ return content;
+}
+
} // namespace
int main(int argc, char *argv[])
@@ -512,6 +542,7 @@ int main(int argc, char *argv[])
QStringList qmlRootPaths;
QStringList scanFiles;
QStringList qmlImportPaths;
+ bool generateCmakeContent = false;
int i = 1;
while (i < args.count()) {
@@ -536,6 +567,8 @@ int main(int argc, char *argv[])
if (i >= args.count())
std::cerr << "-importPath requires an argument\n";
argReceiver = &qmlImportPaths;
+ } else if (arg == QLatin1String("-cmake-output")) {
+ generateCmakeContent = true;
} else {
std::cerr << qPrintable(appName) << ": Invalid argument: \""
<< qPrintable(arg) << "\"\n";
@@ -562,8 +595,15 @@ int main(int argc, char *argv[])
// Find the imports!
QVariantList imports = findQmlImportsRecursively(qmlRootPaths, scanFiles);
- // Convert to JSON
- QByteArray json = QJsonDocument(QJsonArray::fromVariantList(imports)).toJson();
- std::cout << json.constData() << std::endl;
+ QByteArray content;
+ if (generateCmakeContent) {
+ // Convert to CMake code
+ content = generateCmakeIncludeFileContent(imports).toUtf8();
+ } else {
+ // Convert to JSON
+ content = QJsonDocument(QJsonArray::fromVariantList(imports)).toJson();
+ }
+
+ std::cout << content.constData() << std::endl;
return 0;
}
diff --git a/tools/qmlimportscanner/qmlimportscanner.pro b/tools/qmlimportscanner/qmlimportscanner.pro
index 0b3a03abf3..a29b582274 100644
--- a/tools/qmlimportscanner/qmlimportscanner.pro
+++ b/tools/qmlimportscanner/qmlimportscanner.pro
@@ -5,6 +5,51 @@ DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII
SOURCES += main.cpp
+load(cmake_functions)
+
+CMAKE_BIN_DIR = $$cmakeRelativePath($$[QT_HOST_BINS], $$[QT_INSTALL_PREFIX])
+contains(CMAKE_BIN_DIR, "^\\.\\./.*") {
+ CMAKE_BIN_DIR = $$[QT_HOST_BINS]/
+ CMAKE_BIN_DIR_IS_ABSOLUTE = True
+}
+
+CMAKE_QML_DIR = $$cmakeRelativePath($$[QT_INSTALL_QML/get], $$[QT_INSTALL_PREFIX])
+contains(CMAKE_QML_DIR, "^\\.\\./.*") {
+ CMAKE_QML_DIR = $$[QT_INSTALL_QML/get]/
+ CMAKE_QML_DIR_IS_ABSOLUTE = True
+}
+load(qt_build_paths)
+
+static|staticlib:CMAKE_STATIC_TYPE = true
+
+# Compute the platform target suffix.
+CMAKE_QML_PLUGIN_SUFFIX_RELEASE =
+win32: CMAKE_QML_PLUGIN_SUFFIX_DEBUG = d
+else:darwin: CMAKE_QML_PLUGIN_SUFFIX_DEBUG = _debug
+else: CMAKE_QML_PLUGIN_SUFFIX_DEBUG =
+
+# Find out which configurations should be handled in the generated Config.cmake file.
+CMAKE_DEBUG_TYPE =
+CMAKE_RELEASE_TYPE =
+if(qtConfig(debug_and_release)|contains(QT_CONFIG, debug, debug|release)): CMAKE_DEBUG_TYPE = debug
+if(qtConfig(debug_and_release)|contains(QT_CONFIG, release, debug|release)): CMAKE_RELEASE_TYPE = release
+
+qtConfig(debug_and_release) {
+ CMAKE_DEBUG_AND_RELEASE = TRUE
+} else {
+ CMAKE_DEBUG_AND_RELEASE = FALSE
+}
+
+equals(QMAKE_HOST.os, Windows): CMAKE_BIN_SUFFIX = ".exe"
+cmake_config_file.input = $$PWD/Qt5QmlImportScannerConfig.cmake.in
+cmake_config_file.output = $$MODULE_BASE_OUTDIR/lib/cmake/Qt5QmlImportScanner/Qt5QmlImportScannerConfig.cmake
+QMAKE_SUBSTITUTES += cmake_config_file
+
+cmake_build_integration.files = $$cmake_config_file.output $$PWD/Qt5QmlImportScannerTemplate.cpp.in
+cmake_build_integration.path = $$[QT_INSTALL_LIBS]/cmake/Qt5QmlImportScanner
+prefix_build: INSTALLS += cmake_build_integration
+else: COPIES += cmake_build_integration
+
QMAKE_TARGET_DESCRIPTION = QML Import Scanner
load(qt_tool)
diff --git a/tools/qmllint/findunqualified.cpp b/tools/qmllint/findunqualified.cpp
index 0d1cbf5823..27939608d7 100644
--- a/tools/qmllint/findunqualified.cpp
+++ b/tools/qmllint/findunqualified.cpp
@@ -40,7 +40,7 @@
#include <private/qqmljsparser_p.h>
#include <private/qv4codegen_p.h>
-QDebug &operator<<(QDebug dbg, const QQmlJS::AST::SourceLocation &loc);
+QDebug operator<<(QDebug dbg, const QQmlJS::AST::SourceLocation &loc);
static QQmlJS::TypeDescriptionReader createReaderForFile(QString const &filename)
{
@@ -333,7 +333,9 @@ void FindUnqualifiedIDVisitor::importExportedNames(QStringRef prefix, QString na
void FindUnqualifiedIDVisitor::throwRecursionDepthError()
{
- return;
+ m_colorOut.write(QStringLiteral("Error"), Error);
+ m_colorOut.write(QStringLiteral("Maximum statement or expression depth exceeded"), Error);
+ m_visitFailed = true;
}
bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiProgram *)
@@ -449,9 +451,10 @@ void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::CaseBlock *)
leaveEnvironment();
}
-bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::Catch *)
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::Catch *catchStatement)
{
enterEnvironment(ScopeType::JSLexicalScope, "catch");
+ m_currentScope->insertJSIdentifier(catchStatement->patternElement->bindingIdentifier.toString(), QQmlJS::AST::VariableScope::Let);
return true;
}
@@ -568,6 +571,9 @@ FindUnqualifiedIDVisitor::~FindUnqualifiedIDVisitor() = default;
bool FindUnqualifiedIDVisitor::check()
{
+ if (m_visitFailed)
+ return false;
+
// now that all ids are known, revisit any Connections whose target were perviously unknown
for (auto const& outstandingConnection: m_outstandingConnections) {
auto metaObject = m_qmlid2meta[outstandingConnection.targetName];
@@ -767,7 +773,7 @@ void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::UiObjectDefinition *)
leaveEnvironment();
}
-QDebug &operator<<(QDebug dbg, const QQmlJS::AST::SourceLocation &loc)
+QDebug operator<<(QDebug dbg, const QQmlJS::AST::SourceLocation &loc)
{
QDebugStateSaver saver(dbg);
dbg.nospace() << loc.startLine;
diff --git a/tools/qmllint/findunqualified.h b/tools/qmllint/findunqualified.h
index 8fc8257bef..181f42f265 100644
--- a/tools/qmllint/findunqualified.h
+++ b/tools/qmllint/findunqualified.h
@@ -59,6 +59,7 @@ private:
QSet<QPair<QString, QString>> m_alreadySeenImports;
QSet<QString> m_unknownImports;
ColorOutput m_colorOut;
+ bool m_visitFailed = false;
struct OutstandingConnection {QString targetName; ScopeTree *scope; QQmlJS::AST::UiObjectDefinition *uiod;};
diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp
index 464f3e8a6b..f0ed1f8ebe 100644
--- a/tools/qmlplugindump/main.cpp
+++ b/tools/qmlplugindump/main.cpp
@@ -100,21 +100,45 @@ static QString enquote(const QString &string)
.replace(QLatin1Char('"'),QLatin1String("\\\"")));
}
-void collectReachableMetaObjects(const QMetaObject *meta, QSet<const QMetaObject *> *metas, bool extended = false)
+struct QmlVersionInfo
{
+ QString pluginImportUri;
+ int majorVersion;
+ int minorVersion;
+};
+
+static bool matchingImportUri(const QQmlType &ty, const QmlVersionInfo& versionInfo) {
+ return (versionInfo.pluginImportUri == ty.module()
+ && (ty.majorVersion() == versionInfo.majorVersion || ty.majorVersion() == -1))
+ || ty.module().isEmpty();
+}
+
+void collectReachableMetaObjects(const QMetaObject *meta, QSet<const QMetaObject *> *metas, const QmlVersionInfo &info, bool extended = false, bool alreadyChangedModule = false)
+{
+ auto ty = QQmlMetaType::qmlType(meta);
if (! meta || metas->contains(meta))
return;
- // dynamic meta objects can break things badly
- // but extended types are usually fine
- const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate *>(meta->d.data);
- if (extended || !(mop->flags & DynamicMetaObject))
- metas->insert(meta);
+ if (matchingImportUri(ty, info)) {
+ if (!alreadyChangedModule) {
+ // dynamic meta objects can break things badly
+ // but extended types are usually fine
+ const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate *>(meta->d.data);
+ if (extended || !(mop->flags & DynamicMetaObject))
+ metas->insert(meta);
+ } else if (!ty.module().isEmpty()) { // empty module (e.g. from an attached property) would cause a (false) match; do not warn about them
+ qWarning() << "Circular module dependency cannot be expressed in plugin.qmltypes file"
+ << "Object was:" << meta->className()
+ << ty.module() << info.pluginImportUri;
+ }
+ } else if (!ty.module().isEmpty()) {
+ alreadyChangedModule = true;
+ }
- collectReachableMetaObjects(meta->superClass(), metas);
+ collectReachableMetaObjects(meta->superClass(), metas, info, /*extended=*/ false, alreadyChangedModule);
}
-void collectReachableMetaObjects(QObject *object, QSet<const QMetaObject *> *metas)
+void collectReachableMetaObjects(QObject *object, QSet<const QMetaObject *> *metas, const QmlVersionInfo &info)
{
if (! object)
return;
@@ -122,7 +146,7 @@ void collectReachableMetaObjects(QObject *object, QSet<const QMetaObject *> *met
const QMetaObject *meta = object->metaObject();
if (verbose)
std::cerr << "Processing object " << qPrintable( meta->className() ) << std::endl;
- collectReachableMetaObjects(meta, metas);
+ collectReachableMetaObjects(meta, metas, info);
for (int index = 0; index < meta->propertyCount(); ++index) {
QMetaProperty prop = meta->property(index);
@@ -135,17 +159,18 @@ void collectReachableMetaObjects(QObject *object, QSet<const QMetaObject *> *met
// accessing a member of oo is going to cause a segmentation fault
QObject *oo = QQmlMetaType::toQObject(prop.read(object));
if (oo && !metas->contains(oo->metaObject()))
- collectReachableMetaObjects(oo, metas);
+ collectReachableMetaObjects(oo, metas, info);
currentProperty.clear();
}
}
}
-void collectReachableMetaObjects(QQmlEnginePrivate *engine, const QQmlType &ty, QSet<const QMetaObject *> *metas)
+void collectReachableMetaObjects(QQmlEnginePrivate *engine, const QQmlType &ty, QSet<const QMetaObject *> *metas, const QmlVersionInfo& info)
{
- collectReachableMetaObjects(ty.baseMetaObject(), metas, ty.isExtendedType());
- if (ty.attachedPropertiesType(engine))
- collectReachableMetaObjects(ty.attachedPropertiesType(engine), metas);
+ collectReachableMetaObjects(ty.baseMetaObject(), metas, info, ty.isExtendedType());
+ if (ty.attachedPropertiesType(engine) && matchingImportUri(ty, info)) {
+ collectReachableMetaObjects(ty.attachedPropertiesType(engine), metas, info);
+ }
}
/* We want to add the MetaObject for 'Qt' to the list, this is a
@@ -205,13 +230,13 @@ QByteArray convertToId(const QMetaObject *mo)
// Collect all metaobjects for types registered with qmlRegisterType() without parameters
void collectReachableMetaObjectsWithoutQmlName(QQmlEnginePrivate *engine, QSet<const QMetaObject *>& metas,
- QMap<QString, QSet<QQmlType>> &compositeTypes) {
+ QMap<QString, QSet<QQmlType>> &compositeTypes, const QmlVersionInfo &info) {
const auto qmlAllTypes = QQmlMetaType::qmlAllTypes();
for (const QQmlType &ty : qmlAllTypes) {
if (!metas.contains(ty.baseMetaObject())) {
if (!ty.isComposite()) {
- collectReachableMetaObjects(engine, ty, &metas);
- } else {
+ collectReachableMetaObjects(engine, ty, &metas, info);
+ } else if (matchingImportUri(ty, info)) {
compositeTypes[ty.elementName()].insert(ty);
}
}
@@ -222,20 +247,24 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine,
QSet<const QMetaObject *> &noncreatables,
QSet<const QMetaObject *> &singletons,
QMap<QString, QSet<QQmlType>> &compositeTypes,
- const QList<QQmlType> &skip = QList<QQmlType>())
+ const QmlVersionInfo &info,
+ const QList<QQmlType> &skip = QList<QQmlType>()
+ )
{
QSet<const QMetaObject *> metas;
metas.insert(FriendlyQObject::qtMeta());
const auto qmlTypes = QQmlMetaType::qmlTypes();
for (const QQmlType &ty : qmlTypes) {
+ if (!matchingImportUri(ty,info))
+ continue;
if (!ty.isCreatable())
noncreatables.insert(ty.baseMetaObject());
if (ty.isSingleton())
singletons.insert(ty.baseMetaObject());
if (!ty.isComposite()) {
qmlTypesByCppName[ty.baseMetaObject()->className()].insert(ty);
- collectReachableMetaObjects(QQmlEnginePrivate::get(engine), ty, &metas);
+ collectReachableMetaObjects(QQmlEnginePrivate::get(engine), ty, &metas, info);
} else {
compositeTypes[ty.elementName()].insert(ty);
}
@@ -245,6 +274,8 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine,
// find even more QMetaObjects by instantiating QML types and running
// over the instances
for (const QQmlType &ty : qmlTypes) {
+ if (!matchingImportUri(ty, info))
+ continue;
if (skip.contains(ty))
continue;
if (ty.isExtendedType())
@@ -274,7 +305,7 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine,
if (verbose)
std::cerr << "Trying to get singleton for " << qPrintable(tyName)
<< " (" << qPrintable( siinfo->typeName ) << ")" << std::endl;
- collectReachableMetaObjects(object, &metas);
+ collectReachableMetaObjects(object, &metas, info);
object = QQmlEnginePrivate::get(engine)->singletonInstance<QObject*>(ty);
} else {
inObjectInstantiation.clear();
@@ -293,7 +324,7 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine,
if (verbose)
std::cerr << "Got " << qPrintable( tyName )
<< " (" << qPrintable( QString::fromUtf8(ty.typeName()) ) << ")" << std::endl;
- collectReachableMetaObjects(object, &metas);
+ collectReachableMetaObjects(object, &metas, info);
object->deleteLater();
} else {
std::cerr << "Could not create " << qPrintable(tyName) << std::endl;
@@ -301,7 +332,7 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine,
}
}
- collectReachableMetaObjectsWithoutQmlName(QQmlEnginePrivate::get(engine), metas, compositeTypes);
+ collectReachableMetaObjectsWithoutQmlName(QQmlEnginePrivate::get(engine), metas, compositeTypes, info);
return metas;
}
@@ -1186,11 +1217,7 @@ int main(int argc, char *argv[])
QSet<const QMetaObject *> uncreatableMetas;
QSet<const QMetaObject *> singletonMetas;
QMap<QString, QSet<QQmlType>> defaultCompositeTypes;
- QSet<const QMetaObject *> defaultReachable = collectReachableMetaObjects(&engine, uncreatableMetas, singletonMetas, defaultCompositeTypes);
- QList<QQmlType> defaultTypes = QQmlMetaType::qmlTypes();
- // add some otherwise unreachable QMetaObjects
- defaultReachable.insert(&QQuickMouseEvent::staticMetaObject);
// QQuickKeyEvent, QQuickPinchEvent, QQuickDropEvent are not exported
QSet<QByteArray> defaultReachableNames;
@@ -1200,35 +1227,25 @@ int main(int argc, char *argv[])
// composite types we want to dump information of
QMap<QString, QSet<QQmlType>> compositeTypes;
+ int majorVersion = qtQmlMajorVersion, minorVersion = qtQmlMinorVersion;
if (action == Builtins) {
- for (const QMetaObject *m : qAsConst(defaultReachable)) {
- if (m->className() == QLatin1String("Qt")) {
- metas.insert(m);
- break;
- }
- }
- } else if (pluginImportUri == QLatin1String("QtQml")) {
- bool ok = false;
- const uint major = pluginImportVersion.splitRef('.').at(0).toUInt(&ok, 10);
- if (!ok) {
- std::cerr << "Malformed version string \""<< qPrintable(pluginImportVersion) << "\"."
- << std::endl;
- return EXIT_INVALIDARGUMENTS;
- }
- if (major != qtQmlMajorVersion) {
- std::cerr << "Unsupported version \"" << qPrintable(pluginImportVersion)
- << "\": Major version number must be \"" << qtQmlMajorVersion << "\"."
- << std::endl;
- return EXIT_INVALIDARGUMENTS;
- }
- metas = defaultReachable;
- for (const QMetaObject *m : qAsConst(defaultReachable)) {
- if (m->className() == QLatin1String("Qt")) {
- metas.remove(m);
- break;
- }
- }
+ QSet<const QMetaObject *> builtins = collectReachableMetaObjects(&engine, uncreatableMetas, singletonMetas, defaultCompositeTypes, {QLatin1String("Qt"), majorVersion, minorVersion});
+ Q_ASSERT(builtins.size() == 1);
+ metas.insert(*builtins.begin());
} else {
+ auto versionSplitted = pluginImportVersion.split(".");
+ bool ok = versionSplitted.size() == 2;
+ if (!ok)
+ qCritical("Invalid version number");
+ else {
+ majorVersion = versionSplitted.at(0).toInt(&ok);
+ if (!ok)
+ qCritical("Invalid major version");
+ minorVersion = versionSplitted.at(1).toInt(&ok);
+ if (!ok)
+ qCritical("Invalid minor version");
+ }
+ QList<QQmlType> defaultTypes = QQmlMetaType::qmlTypes();
// find a valid QtQuick import
QByteArray importCode;
QQmlType qtObjectType = QQmlMetaType::qmlType(&QObject::staticMetaObject);
@@ -1273,8 +1290,7 @@ int main(int argc, char *argv[])
}
}
- QSet<const QMetaObject *> candidates = collectReachableMetaObjects(&engine, uncreatableMetas, singletonMetas, compositeTypes, defaultTypes);
- candidates.subtract(defaultReachable);
+ QSet<const QMetaObject *> candidates = collectReachableMetaObjects(&engine, uncreatableMetas, singletonMetas, compositeTypes, {pluginImportUri, majorVersion, minorVersion}, defaultTypes);
for (QString iter: compositeTypes.keys()) {
if (defaultCompositeTypes.contains(iter)) {
@@ -1284,13 +1300,8 @@ int main(int argc, char *argv[])
}
}
- // Also eliminate meta objects with the same classname.
- // This is required because extended objects seem not to share
- // a single meta object instance.
- for (const QMetaObject *mo : qAsConst(defaultReachable))
- defaultReachableNames.insert(QByteArray(mo->className()));
for (const QMetaObject *mo : qAsConst(candidates)) {
- if (!defaultReachableNames.contains(mo->className()))
+ if (mo->className() != QLatin1String("Qt"))
metas.insert(mo);
}
}