aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--.tag2
-rw-r--r--examples/quick/positioners/positioners-attachedproperties.qml28
-rw-r--r--examples/quick/scenegraph/rendernode/openglrenderer.cpp6
-rw-r--r--examples/quick/tutorials/dynamicview/dynamicview1/dynamicview.qml6
-rw-r--r--src/3rdparty/masm/assembler/ARM64Assembler.h2
-rw-r--r--src/3rdparty/masm/assembler/X86Assembler.h4
-rw-r--r--src/3rdparty/masm/wtf/OSAllocatorPosix.cpp18
-rw-r--r--src/imports/labsmodels/qqmltablemodelcolumn_p.h2
-rw-r--r--src/imports/layouts/qquickstacklayout.cpp28
-rw-r--r--src/imports/layouts/qquickstacklayout_p.h3
-rw-r--r--src/imports/statemachine/signaltransition.cpp10
-rw-r--r--src/imports/testlib/quicktestevent.cpp5
-rw-r--r--src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp6
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservicefactory.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_server/qmldbg_server.pro2
-rw-r--r--src/plugins/qmltooling/qmldbg_server/qqmldebugserverfactory.cpp (renamed from src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp)2
-rw-r--r--src/qml/animations/qabstractanimationjob.cpp41
-rw-r--r--src/qml/animations/qabstractanimationjob_p.h3
-rw-r--r--src/qml/common/common.pri6
-rw-r--r--src/qml/common/qqmljsfixedpoolarray_p.h2
-rw-r--r--src/qml/common/qv4compileddata_p.h372
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp189
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h4
-rw-r--r--src/qml/compiler/qv4bytecodegenerator_p.h4
-rw-r--r--src/qml/compiler/qv4codegen.cpp11
-rw-r--r--src/qml/compiler/qv4compiler.cpp43
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions.cpp5
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions_p.h7
-rw-r--r--src/qml/configure.pri2
-rw-r--r--src/qml/debugger/debugger.pri1
-rw-r--r--src/qml/debugger/qqmldebug.cpp13
-rw-r--r--src/qml/debugger/qqmldebugconnector.cpp2
-rw-r--r--src/qml/debugger/qqmldebugconnector_p.h1
-rw-r--r--src/qml/debugger/qqmldebugserver.cpp49
-rw-r--r--src/qml/debugger/qqmldebugserver_p.h1
-rw-r--r--src/qml/debugger/qqmlprofiler_p.h2
-rw-r--r--src/qml/doc/src/javascript/finetuning.qdoc9
-rw-r--r--src/qml/inlinecomponentutils_p.h56
-rw-r--r--src/qml/jit/qv4assemblercommon.cpp4
-rw-r--r--src/qml/jit/qv4assemblercommon_p.h4
-rw-r--r--src/qml/jit/qv4baselineassembler.cpp4
-rw-r--r--src/qml/jit/qv4baselineassembler_p.h4
-rw-r--r--src/qml/jit/qv4baselinejit.cpp5
-rw-r--r--src/qml/jit/qv4baselinejit_p.h4
-rw-r--r--src/qml/jsruntime/qv4arrayiterator.cpp6
-rw-r--r--src/qml/jsruntime/qv4engine.cpp40
-rw-r--r--src/qml/jsruntime/qv4engine_p.h13
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit.cpp59
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit_p.h2
-rw-r--r--src/qml/jsruntime/qv4function.cpp3
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp11
-rw-r--r--src/qml/jsruntime/qv4global_p.h1
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp170
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h38
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp113
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h48
-rw-r--r--src/qml/jsruntime/qv4object.cpp59
-rw-r--r--src/qml/jsruntime/qv4profiling.cpp4
-rw-r--r--src/qml/jsruntime/qv4promiseobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4propertykey_p.h5
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp13
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp24
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h2
-rw-r--r--src/qml/jsruntime/qv4reflect.cpp5
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp5
-rw-r--r--src/qml/memory/qv4mm.cpp2
-rw-r--r--src/qml/qml/qqmlbinding.cpp8
-rw-r--r--src/qml/qml/qqmlcomponent.cpp7
-rw-r--r--src/qml/qml/qqmlcomponentattached_p.h1
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp4
-rw-r--r--src/qml/qml/qqmlengine.cpp6
-rw-r--r--src/qml/qml/qqmlengine_p.h4
-rw-r--r--src/qml/qml/qqmlimport.cpp1
-rw-r--r--src/qml/qml/qqmlincubator.cpp14
-rw-r--r--src/qml/qml/qqmlirloader.cpp11
-rw-r--r--src/qml/qml/qqmlloggingcategory.cpp17
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp119
-rw-r--r--src/qml/qml/qqmlprivate.h39
-rw-r--r--src/qml/qml/qqmlproperty.cpp8
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp4
-rw-r--r--src/qml/qml/qqmlpropertycachecreator.cpp13
-rw-r--r--src/qml/qml/qqmlpropertycachecreator_p.h122
-rw-r--r--src/qml/qml/qqmlpropertyvalidator.cpp85
-rw-r--r--src/qml/qml/qqmlscriptblob.cpp8
-rw-r--r--src/qml/qml/qqmltypecompiler.cpp133
-rw-r--r--src/qml/qml/qqmltypedata.cpp45
-rw-r--r--src/qml/qml/qqmltypeloader.cpp4
-rw-r--r--src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp2
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp13
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp27
-rw-r--r--src/qml/qtqmlglobal_p.h22
-rw-r--r--src/qml/types/qqmlconnections.cpp13
-rw-r--r--src/qml/util/qqmlpropertymap.cpp2
-rw-r--r--src/qmldebug/qmldebug.pro1
-rw-r--r--src/qmldebug/qqmldebugclient.cpp2
-rw-r--r--src/qmldebug/qqmldebugmessageclient.cpp2
-rw-r--r--src/qmldebug/qqmldebugtranslationclient.cpp2
-rw-r--r--src/qmldebug/qqmlenginedebugclient.cpp2
-rw-r--r--src/qmldebug/qqmlinspectorclient.cpp2
-rw-r--r--src/qmldebug/qqmlpreviewclient.cpp2
-rw-r--r--src/qmldebug/qqmlprofilereventreceiver.cpp49
-rw-r--r--src/qmldebug/qqmlprofilereventreceiver_p.h3
-rw-r--r--src/qmldebug/qv4debugclient.cpp2
-rw-r--r--src/qmlmodels/qqmlabstractdelegatecomponent.cpp2
-rw-r--r--src/qmlmodels/qqmladaptormodel.cpp18
-rw-r--r--src/qmlmodels/qqmladaptormodel_p.h6
-rw-r--r--src/qmlmodels/qqmldelegatemodel.cpp5
-rw-r--r--src/qmlmodels/qqmlinstantiator.cpp2
-rw-r--r--src/qmlmodels/qqmllistcompositor_p.h5
-rw-r--r--src/qmlmodels/qqmllistmodel.cpp19
-rw-r--r--src/qmltest/quicktest.cpp12
-rw-r--r--src/qmltest/quicktestresult.cpp3
-rw-r--r--src/qmltyperegistrar/qmltypes.prf20
-rw-r--r--src/quick/accessible/qaccessiblequickitem.cpp7
-rw-r--r--src/quick/doc/images/containmentMask-circle.gifbin0 -> 9926 bytes
-rw-r--r--src/quick/doc/images/containmentMask-shape.gifbin0 -> 11261 bytes
-rw-r--r--src/quick/doc/snippets/pointerHandlers/hoverModifiers.qml69
-rw-r--r--src/quick/doc/snippets/pointerHandlers/hoverMouseOrStylus.qml69
-rw-r--r--src/quick/doc/snippets/pointerHandlers/hoverStylusOrEraser.qml76
-rw-r--r--src/quick/doc/snippets/pointerHandlers/images/cursor-eraser.pngbin0 -> 1454 bytes
-rw-r--r--src/quick/doc/snippets/qml/item/containmentMask-circle-js.qml71
-rw-r--r--src/quick/doc/snippets/qml/item/containmentMask-shape.qml80
-rw-r--r--src/quick/doc/src/concepts/input/focus.qdoc2
-rw-r--r--src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc27
-rw-r--r--src/quick/handlers/qquickdragaxis.cpp2
-rw-r--r--src/quick/handlers/qquickdraghandler.cpp2
-rw-r--r--src/quick/handlers/qquickhandlerpoint.cpp2
-rw-r--r--src/quick/handlers/qquickhoverhandler.cpp108
-rw-r--r--src/quick/handlers/qquickhoverhandler_p.h1
-rw-r--r--src/quick/handlers/qquickmultipointhandler.cpp2
-rw-r--r--src/quick/handlers/qquickpinchhandler.cpp5
-rw-r--r--src/quick/handlers/qquickpointerdevicehandler.cpp2
-rw-r--r--src/quick/handlers/qquickpointerhandler.cpp28
-rw-r--r--src/quick/handlers/qquickpointhandler.cpp2
-rw-r--r--src/quick/handlers/qquicksinglepointhandler.cpp2
-rw-r--r--src/quick/handlers/qquicktaphandler.cpp2
-rw-r--r--src/quick/handlers/qquickwheelhandler.cpp2
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp29
-rw-r--r--src/quick/items/context2d/qquickcontext2d_p.h2
-rw-r--r--src/quick/items/qquickaccessibleattached.cpp5
-rw-r--r--src/quick/items/qquickanimatedsprite.cpp14
-rw-r--r--src/quick/items/qquickevents.cpp4
-rw-r--r--src/quick/items/qquickflickable.cpp131
-rw-r--r--src/quick/items/qquickflickable_p_p.h6
-rw-r--r--src/quick/items/qquickgridview.cpp2
-rw-r--r--src/quick/items/qquickimage.cpp4
-rw-r--r--src/quick/items/qquickitem.cpp44
-rw-r--r--src/quick/items/qquickitemsmodule.cpp2
-rw-r--r--src/quick/items/qquickitemview.cpp6
-rw-r--r--src/quick/items/qquickitemviewtransition.cpp10
-rw-r--r--src/quick/items/qquickitemviewtransition_p.h4
-rw-r--r--src/quick/items/qquickloader.cpp28
-rw-r--r--src/quick/items/qquickloader_p_p.h1
-rw-r--r--src/quick/items/qquickmousearea.cpp6
-rw-r--r--src/quick/items/qquickmultipointtoucharea.cpp33
-rw-r--r--src/quick/items/qquickmultipointtoucharea_p.h7
-rw-r--r--src/quick/items/qquickpincharea.cpp14
-rw-r--r--src/quick/items/qquickscalegrid.cpp2
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp8
-rw-r--r--src/quick/items/qquickshadereffectsource_p.h1
-rw-r--r--src/quick/items/qquicktableview.cpp2
-rw-r--r--src/quick/items/qquicktext.cpp36
-rw-r--r--src/quick/items/qquicktext_p.h2
-rw-r--r--src/quick/items/qquicktextedit.cpp10
-rw-r--r--src/quick/items/qquicktextedit_p.h2
-rw-r--r--src/quick/items/qquicktextinput.cpp46
-rw-r--r--src/quick/items/qquickwindow.cpp28
-rw-r--r--src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp2
-rw-r--r--src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp2
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp72
-rw-r--r--src/quick/scenegraph/coreapi/qsggeometry.h1
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterialrhishader.cpp2
-rw-r--r--src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp2
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h4
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.cpp32
-rw-r--r--src/quick/scenegraph/qsgdefaultrendercontext.cpp15
-rw-r--r--src/quick/scenegraph/qsgdefaultrendercontext_p.h1
-rw-r--r--src/quick/scenegraph/qsgopengldistancefieldglyphcache.cpp10
-rw-r--r--src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp16
-rw-r--r--src/quick/scenegraph/qsgrhishadereffectnode.cpp4
-rw-r--r--src/quick/scenegraph/qsgrhishadereffectnode_p.h1
-rw-r--r--src/quick/scenegraph/qsgrhitextureglyphcache.cpp5
-rw-r--r--src/quick/scenegraph/shaders/outlinedtext.vert9
-rw-r--r--src/quick/scenegraph/shaders/outlinedtext_core.vert9
-rw-r--r--src/quick/scenegraph/shaders/styledtext.vert7
-rw-r--r--src/quick/scenegraph/shaders/styledtext_core.vert7
-rw-r--r--src/quick/scenegraph/shaders/textmask.vert7
-rw-r--r--src/quick/scenegraph/shaders/textmask_core.vert7
-rw-r--r--src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsbbin1469 -> 1579 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsbbin1344 -> 1436 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsbbin1351 -> 1433 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsbbin845 -> 926 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsbbin2174 -> 2266 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsbbin2623 -> 2743 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsbbin1437 -> 1528 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/styledtext.frag.qsbbin1740 -> 1834 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/styledtext.vert.qsbbin2175 -> 2294 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsbbin1158 -> 1236 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/textmask.frag.qsbbin1469 -> 1561 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/textmask.vert.qsbbin1933 -> 2047 bytes
-rw-r--r--src/quick/scenegraph/util/qsgplaintexture.cpp2
-rw-r--r--src/quick/util/qquickanimatorjob.cpp11
-rw-r--r--src/quick/util/qquickanimatorjob_p.h11
-rw-r--r--src/quick/util/qquickpropertychanges.cpp35
-rw-r--r--src/quick/util/qquicksmoothedanimation.cpp2
-rw-r--r--src/quick/util/qquickstategroup.cpp9
-rw-r--r--src/quick/util/qquickstyledtext.cpp2
-rw-r--r--src/quick/util/qquicktimeline.cpp5
-rw-r--r--src/quickshapes/qquickshape.cpp15
-rw-r--r--src/quickshapes/qquickshapegenericrenderer.cpp6
-rw-r--r--src/quickwidgets/qquickwidget.cpp7
-rw-r--r--tests/auto/cmake/qtquickcompiler/main.cpp2
-rw-r--r--tests/auto/qml/animation/qparallelanimationgroupjob/BLACKLIST3
-rw-r--r--tests/auto/qml/animation/qpauseanimationjob/BLACKLIST3
-rw-r--r--tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp4
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp140
-rw-r--r--tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp6
-rw-r--r--tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp3
-rw-r--r--tests/auto/qml/qqmlconsole/data/assert.qml13
-rw-r--r--tests/auto/qml/qqmlconsole/data/categorized_logging.qml9
-rw-r--r--tests/auto/qml/qqmlconsole/data/exception.qml4
-rw-r--r--tests/auto/qml/qqmlconsole/data/logging.qml21
-rw-r--r--tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp27
-rw-r--r--tests/auto/qml/qqmlecmascript/data/functionAsDefaultArgument.qml8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/internalClassParentGc.js29
-rw-r--r--tests/auto/qml/qqmlecmascript/data/internalClassParentGc.qml13
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp35
-rw-r--r--tests/auto/qml/qqmlinstantiator/data/activeModelChangeInteraction.qml39
-rw-r--r--tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp21
-rw-r--r--tests/auto/qml/qqmllanguage/data/Broken.qml5
-rw-r--r--tests/auto/qml/qqmllanguage/data/ComponentType.qml8
-rw-r--r--tests/auto/qml/qqmllanguage/data/alias.15a.qml33
-rw-r--r--tests/auto/qml/qqmllanguage/data/ambiguousBinding/TestCase.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/ambiguousBinding/ambiguousContainingType.qml3
-rw-r--r--tests/auto/qml/qqmllanguage/data/asBroken.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/badGroupedProperty.qml10
-rw-r--r--tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl.qml11
-rw-r--r--tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl2.qml11
-rw-r--r--tests/auto/qml/qqmllanguage/data/fuzzed.1.errors.txt3
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.cpp2
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp111
-rw-r--r--tests/auto/qml/qqmllistcompositor/tst_qqmllistcompositor.cpp8
-rw-r--r--tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp15
-rw-r--r--tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp14
-rw-r--r--tests/auto/qml/qv4assembler/tst_qv4assembler.cpp3
-rw-r--r--tests/auto/qml/qv4mm/tst_qv4mm.cpp95
-rw-r--r--tests/auto/qmltest/events/tst_wheel.qml2
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragMargin.qml3
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp12
-rw-r--r--tests/auto/quick/pointerhandlers/qquickhoverhandler/data/windowCursorShape.qml13
-rw-r--r--tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp23
-rw-r--r--tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp1
-rw-r--r--tests/auto/quick/qquickanimations/BLACKLIST3
-rw-r--r--tests/auto/quick/qquickanimations/data/cleanupWhenRenderThreadStops.qml32
-rw-r--r--tests/auto/quick/qquickanimations/tst_qquickanimations.cpp14
-rw-r--r--tests/auto/quick/qquickbehaviors/BLACKLIST3
-rw-r--r--tests/auto/quick/qquickdroparea/BLACKLIST4
-rw-r--r--tests/auto/quick/qquickflickable/data/contentPosWhileDragging.qml22
-rw-r--r--tests/auto/quick/qquickflickable/tst_qquickflickable.cpp122
-rw-r--r--tests/auto/quick/qquickframebufferobject/BLACKLIST1
-rw-r--r--tests/auto/quick/qquickgridview/data/qtbug92998.qml52
-rw-r--r--tests/auto/quick/qquickgridview/tst_qquickgridview.cpp19
-rw-r--r--tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp22
-rw-r--r--tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml463
-rw-r--r--tests/auto/quick/qquicklistview/BLACKLIST2
-rw-r--r--tests/auto/quick/qquicklistview/data/qtbug86744.qml21
-rw-r--r--tests/auto/quick/qquicklistview/data/qtbug_92809.qml119
-rw-r--r--tests/auto/quick/qquicklistview/data/singletonModelLifetime.qml32
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp51
-rw-r--r--tests/auto/quick/qquickloader/BLACKLIST1
-rw-r--r--tests/auto/quick/qquickloader/data/noEngine.qml32
-rw-r--r--tests/auto/quick/qquickloader/data/overflow.qml5
-rw-r--r--tests/auto/quick/qquickloader/tst_qquickloader.cpp28
-rw-r--r--tests/auto/quick/qquickmousearea/data/doubleClickToHide.qml19
-rw-r--r--tests/auto/quick/qquickmousearea/data/preventStealingListViewChild.qml31
-rw-r--r--tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp62
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/BLACKLIST4
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/data/nestedMouseArea.qml26
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/data/nestedPinchArea.qml44
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp66
-rw-r--r--tests/auto/quick/qquickstates/data/noStateOsciallation.qml22
-rw-r--r--tests/auto/quick/qquickstates/tst_qquickstates.cpp15
-rw-r--r--tests/auto/quick/qquicktext/data/fontSizeMode.qml2
-rw-r--r--tests/auto/quick/qquicktext/data/padding.qml26
-rw-r--r--tests/auto/quick/qquicktext/data/paddingInLoader.qml14
-rw-r--r--tests/auto/quick/qquicktext/tst_qquicktext.cpp85
-rw-r--r--tests/auto/quick/qquickvisualdatamodel/data/setDelegateNoDoubleChange.qml43
-rw-r--r--tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp15
-rw-r--r--tests/baseline/scenegraph/data/text/text_nativerendering_no_antialiasing.qml25
-rw-r--r--tests/manual/touch/flicktext.qml30
-rw-r--r--tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in11
-rw-r--r--tools/qmlcachegen/qmlcachegen.cpp4
-rw-r--r--tools/qmlimportscanner/main.cpp6
-rw-r--r--tools/qmlplugindump/main.cpp12
306 files changed, 5032 insertions, 1240 deletions
diff --git a/.qmake.conf b/.qmake.conf
index aa20cb26e7..65ef03633e 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -4,4 +4,4 @@ CONFIG += warning_clean
DEFINES += QT_NO_LINKED_LIST
DEFINES += QT_NO_JAVA_STYLE_ITERATORS
-MODULE_VERSION = 5.15.7
+MODULE_VERSION = 5.15.13
diff --git a/.tag b/.tag
index 6828f88dcb..8b42f85cf5 100644
--- a/.tag
+++ b/.tag
@@ -1 +1 @@
-$Format:%H$
+$Format:%T$
diff --git a/examples/quick/positioners/positioners-attachedproperties.qml b/examples/quick/positioners/positioners-attachedproperties.qml
index af89543289..38c71068f2 100644
--- a/examples/quick/positioners/positioners-attachedproperties.qml
+++ b/examples/quick/positioners/positioners-attachedproperties.qml
@@ -90,14 +90,14 @@ Rectangle {
anchors.leftMargin: 20
anchors.verticalCenter: parent.verticalCenter
text: "Index: " + parent.Positioner.index
- + (parent.Positioner.isFirstItem ? " (First)" : "")
- + (parent.Positioner.isLastItem ? " (Last)" : "")
+ + (parent.Positioner.isFirstItem ? " (First)" : "")
+ + (parent.Positioner.isLastItem ? " (Last)" : "")
}
// When mouse is clicked, display the values of the positioner
MouseArea {
- anchors.fill: parent
- onClicked: column.showInfo(green.Positioner)
+ anchors.fill: parent
+ onClicked: column.showInfo(green.Positioner)
}
}
//! [0]
@@ -113,14 +113,14 @@ Rectangle {
anchors.leftMargin: 20
anchors.verticalCenter: parent.verticalCenter
text: "Index: " + parent.Positioner.index
- + (parent.Positioner.isFirstItem ? " (First)" : "")
- + (parent.Positioner.isLastItem ? " (Last)" : "")
+ + (parent.Positioner.isFirstItem ? " (First)" : "")
+ + (parent.Positioner.isLastItem ? " (Last)" : "")
}
// When mouse is clicked, display the values of the positioner
MouseArea {
- anchors.fill: parent
- onClicked: column.showInfo(blue.Positioner)
+ anchors.fill: parent
+ onClicked: column.showInfo(blue.Positioner)
}
}
@@ -135,14 +135,14 @@ Rectangle {
anchors.leftMargin: 20
anchors.verticalCenter: parent.verticalCenter
text: "Index: " + parent.Positioner.index
- + (parent.Positioner.isFirstItem ? " (First)" : "")
- + (parent.Positioner.isLastItem ? " (Last)" : "")
+ + (parent.Positioner.isFirstItem ? " (First)" : "")
+ + (parent.Positioner.isLastItem ? " (Last)" : "")
}
// When mouse is clicked, display the values of the positioner
MouseArea {
- anchors.fill: parent
- onClicked: column.showInfo(purple.Positioner)
+ anchors.fill: parent
+ onClicked: column.showInfo(purple.Positioner)
}
}
@@ -159,8 +159,8 @@ Rectangle {
anchors.leftMargin: 20
anchors.verticalCenter: parent.verticalCenter
text: "Index: " + parent.Positioner.index
- + (parent.Positioner.isFirstItem ? " (First)" : "")
- + (parent.Positioner.isLastItem ? " (Last)" : "")
+ + (parent.Positioner.isFirstItem ? " (First)" : "")
+ + (parent.Positioner.isLastItem ? " (Last)" : "")
}
}
diff --git a/examples/quick/scenegraph/rendernode/openglrenderer.cpp b/examples/quick/scenegraph/rendernode/openglrenderer.cpp
index a4e619bea9..80806d51d1 100644
--- a/examples/quick/scenegraph/rendernode/openglrenderer.cpp
+++ b/examples/quick/scenegraph/rendernode/openglrenderer.cpp
@@ -158,6 +158,10 @@ void OpenGLRenderNode::render(const RenderState *state)
f->glEnable(GL_BLEND);
f->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ // Regardless of flags() returning DepthAwareRendering or not,
+ // we have to test against what's in the depth buffer already.
+ f->glEnable(GL_DEPTH_TEST);
+
// Clip support.
if (state->scissorEnabled()) {
f->glEnable(GL_SCISSOR_TEST);
@@ -177,7 +181,7 @@ void OpenGLRenderNode::render(const RenderState *state)
//! [4]
QSGRenderNode::StateFlags OpenGLRenderNode::changedStates() const
{
- return BlendState | ScissorState | StencilState;
+ return BlendState | ScissorState | StencilState | DepthState;
}
QSGRenderNode::RenderingFlags OpenGLRenderNode::flags() const
diff --git a/examples/quick/tutorials/dynamicview/dynamicview1/dynamicview.qml b/examples/quick/tutorials/dynamicview/dynamicview1/dynamicview.qml
index 60167aa813..3db55a51a3 100644
--- a/examples/quick/tutorials/dynamicview/dynamicview1/dynamicview.qml
+++ b/examples/quick/tutorials/dynamicview/dynamicview1/dynamicview.qml
@@ -63,7 +63,11 @@ Rectangle {
Rectangle {
id: content
- anchors { left: parent.left; right: parent.right }
+ anchors {
+ left: parent ? parent.left : undefined
+ right: parent ? parent.right : undefined
+ }
+
height: column.implicitHeight + 4
border.width: 1
diff --git a/src/3rdparty/masm/assembler/ARM64Assembler.h b/src/3rdparty/masm/assembler/ARM64Assembler.h
index ca6b33d39a..3e988a277c 100644
--- a/src/3rdparty/masm/assembler/ARM64Assembler.h
+++ b/src/3rdparty/masm/assembler/ARM64Assembler.h
@@ -676,11 +676,11 @@ public:
struct RealTypes {
int64_t m_from : 48;
int64_t m_to : 48;
+ RegisterID m_compareRegister;
JumpType m_type : 8;
JumpLinkType m_linkType : 8;
Condition m_condition : 4;
unsigned m_bitNumber : 6;
- RegisterID m_compareRegister : 6;
bool m_is64Bit : 1;
} realTypes;
} data;
diff --git a/src/3rdparty/masm/assembler/X86Assembler.h b/src/3rdparty/masm/assembler/X86Assembler.h
index e8ae687036..8f9ee29a4d 100644
--- a/src/3rdparty/masm/assembler/X86Assembler.h
+++ b/src/3rdparty/masm/assembler/X86Assembler.h
@@ -201,12 +201,12 @@ private:
TwoByteOpcodeID jccRel32(Condition cond)
{
- return (TwoByteOpcodeID)(OP2_JCC_rel32 + cond);
+ return (TwoByteOpcodeID)(int(OP2_JCC_rel32) + cond);
}
TwoByteOpcodeID setccOpcode(Condition cond)
{
- return (TwoByteOpcodeID)(OP_SETCC + cond);
+ return (TwoByteOpcodeID)(int(OP_SETCC) + cond);
}
typedef enum {
diff --git a/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp b/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp
index d59fdcd675..b5c5f6a2b0 100644
--- a/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp
+++ b/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp
@@ -111,7 +111,11 @@ void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable,
(fd == -1 ? MAP_ANON : 0), fd, 0);
if (result == MAP_FAILED)
CRASH();
- madvise(result, bytes, MADV_DONTNEED);
+
+ while (madvise(result, bytes, MADV_DONTNEED)) {
+ if (errno != EAGAIN)
+ CRASH();
+ }
if (fd != -1)
close(fd);
@@ -218,7 +222,12 @@ void OSAllocator::commit(void* address, size_t bytes, bool writable, bool execut
protection |= PROT_EXEC;
if (mprotect(address, bytes, protection))
CRASH();
- madvise(address, bytes, MADV_WILLNEED);
+
+ while (madvise(address, bytes, MADV_WILLNEED)) {
+ if (errno != EAGAIN)
+ break; // We don't have to crash here. MADV_WILLNEED is only advisory
+ }
+
#elif HAVE(MADV_FREE_REUSE)
UNUSED_PARAM(writable);
UNUSED_PARAM(executable);
@@ -238,7 +247,10 @@ void OSAllocator::decommit(void* address, size_t bytes)
// Use PROT_NONE and MAP_LAZY to decommit the pages.
mmap(address, bytes, PROT_NONE, MAP_FIXED | MAP_LAZY | MAP_PRIVATE | MAP_ANON, -1, 0);
#elif OS(LINUX)
- madvise(address, bytes, MADV_DONTNEED);
+ while (madvise(address, bytes, MADV_DONTNEED)) {
+ if (errno != EAGAIN)
+ CRASH();
+ }
if (mprotect(address, bytes, PROT_NONE))
CRASH();
#elif HAVE(MADV_FREE_REUSE)
diff --git a/src/imports/labsmodels/qqmltablemodelcolumn_p.h b/src/imports/labsmodels/qqmltablemodelcolumn_p.h
index a18f21ab4f..5f6cf9a728 100644
--- a/src/imports/labsmodels/qqmltablemodelcolumn_p.h
+++ b/src/imports/labsmodels/qqmltablemodelcolumn_p.h
@@ -213,8 +213,6 @@ Q_SIGNALS:
void setSizeHintChanged();
private:
- int mIndex = -1;
-
// We store these in hashes because QQuickTableModel needs string-based lookup in certain situations.
QHash<QString, QJSValue> mGetters;
QHash<QString, QJSValue> mSetters;
diff --git a/src/imports/layouts/qquickstacklayout.cpp b/src/imports/layouts/qquickstacklayout.cpp
index d6ee4afe84..d127488b82 100644
--- a/src/imports/layouts/qquickstacklayout.cpp
+++ b/src/imports/layouts/qquickstacklayout.cpp
@@ -171,6 +171,7 @@ void QQuickStackLayout::itemChange(QQuickItem::ItemChange change, const QQuickIt
QQuickLayout::itemChange(change, value);
if (change == ItemChildRemovedChange) {
+ m_cachedItemSizeHints.remove(value.item);
invalidate();
} else if (change == ItemChildAddedChange) {
invalidate();
@@ -192,10 +193,8 @@ QSizeF QQuickStackLayout::sizeHint(Qt::SizeHint whichSizeHint) const
maxS = QSizeF(std::numeric_limits<qreal>::infinity(), std::numeric_limits<qreal>::infinity());
const int count = itemCount();
- m_cachedItemSizeHints.resize(count);
for (int i = 0; i < count; ++i) {
- SizeHints &hints = m_cachedItemSizeHints[i];
- QQuickStackLayout::collectItemSizeHints(itemAt(i), hints.array);
+ SizeHints &hints = cachedItemSizeHints(i);
minS = minS.expandedTo(hints.min());
prefS = prefS.expandedTo(hints.pref());
//maxS = maxS.boundedTo(hints.max()); // Can be resized to be larger than any of its items.
@@ -256,11 +255,12 @@ void QQuickStackLayout::setAlignment(QQuickItem * /*item*/, Qt::Alignment /*alig
void QQuickStackLayout::invalidate(QQuickItem *childItem)
{
- const int indexOfChild = indexOf(childItem);
- if (indexOfChild >= 0 && indexOfChild < m_cachedItemSizeHints.count()) {
- m_cachedItemSizeHints[indexOfChild].min() = QSizeF();
- m_cachedItemSizeHints[indexOfChild].pref() = QSizeF();
- m_cachedItemSizeHints[indexOfChild].max() = QSizeF();
+ ensureLayoutItemsUpdated();
+ if (childItem) {
+ SizeHints &hints = m_cachedItemSizeHints[childItem];
+ hints.min() = QSizeF();
+ hints.pref() = QSizeF();
+ hints.max() = QSizeF();
}
for (int i = 0; i < Qt::NSizeHints; ++i)
@@ -294,6 +294,16 @@ void QQuickStackLayout::updateLayoutItems()
}
}
+QQuickStackLayout::SizeHints &QQuickStackLayout::cachedItemSizeHints(int index) const
+{
+ QQuickItem *item = itemAt(index);
+ Q_ASSERT(item);
+ SizeHints &hints = m_cachedItemSizeHints[item]; // will create an entry if it doesn't exist
+ if (!hints.min().isValid())
+ QQuickStackLayout::collectItemSizeHints(item, hints.array);
+ return hints;
+}
+
void QQuickStackLayout::rearrange(const QSizeF &newSize)
{
Q_D(QQuickStackLayout);
@@ -305,7 +315,7 @@ void QQuickStackLayout::rearrange(const QSizeF &newSize)
if (d->currentIndex == -1 || d->currentIndex >= m_cachedItemSizeHints.count())
return;
- QQuickStackLayout::SizeHints &hints = m_cachedItemSizeHints[d->currentIndex];
+ QQuickStackLayout::SizeHints &hints = cachedItemSizeHints(d->currentIndex);
QQuickItem *item = itemAt(d->currentIndex);
Q_ASSERT(item);
item->setPosition(QPointF(0,0)); // ### respect alignment?
diff --git a/src/imports/layouts/qquickstacklayout_p.h b/src/imports/layouts/qquickstacklayout_p.h
index 0319e259d4..d8feecc11b 100644
--- a/src/imports/layouts/qquickstacklayout_p.h
+++ b/src/imports/layouts/qquickstacklayout_p.h
@@ -95,8 +95,9 @@ private:
QSizeF array[Qt::NSizeHints];
} SizeHints;
- mutable QVector<SizeHints> m_cachedItemSizeHints;
+ mutable QHash<QQuickItem*, SizeHints> m_cachedItemSizeHints;
mutable QSizeF m_cachedSizeHints[Qt::NSizeHints];
+ SizeHints &cachedItemSizeHints(int index) const;
};
class QQuickStackLayoutPrivate : public QQuickLayoutPrivate
diff --git a/src/imports/statemachine/signaltransition.cpp b/src/imports/statemachine/signaltransition.cpp
index 8c37f8368f..dcebb21b41 100644
--- a/src/imports/statemachine/signaltransition.cpp
+++ b/src/imports/statemachine/signaltransition.cpp
@@ -166,12 +166,16 @@ void SignalTransition::connectTriggered()
Q_ASSERT(m_bindings.count() == 1);
const QV4::CompiledData::Binding *binding = m_bindings.at(0);
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script);
+ Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Script);
QV4::ExecutionEngine *jsEngine = QQmlEngine::contextForObject(this)->engine()->handle();
QV4::Scope scope(jsEngine);
QV4::Scoped<QV4::QObjectMethod> qobjectSignal(scope, QJSValuePrivate::convertedToValue(jsEngine, m_signal));
- Q_ASSERT(qobjectSignal);
+ if (!qobjectSignal) {
+ m_signalExpression.take(nullptr);
+ return;
+ }
+
QMetaMethod metaMethod = target->metaObject()->method(qobjectSignal->methodIndex());
int signalIndex = QMetaObjectPrivate::signalIndex(metaMethod);
@@ -198,7 +202,7 @@ void SignalTransitionParser::verifyBindings(const QQmlRefPointer<QV4::Executable
return;
}
- if (binding->type != QV4::CompiledData::Binding::Type_Script) {
+ if (binding->type() != QV4::CompiledData::Binding::Type_Script) {
error(binding, SignalTransition::tr("SignalTransition: script expected"));
return;
}
diff --git a/src/imports/testlib/quicktestevent.cpp b/src/imports/testlib/quicktestevent.cpp
index f2d7f93d26..59b7f15946 100644
--- a/src/imports/testlib/quicktestevent.cpp
+++ b/src/imports/testlib/quicktestevent.cpp
@@ -231,8 +231,10 @@ namespace QtQuickTest
QTEST_ASSERT(item);
if (delay == -1 || delay < QTest::defaultMouseDelay())
delay = QTest::defaultMouseDelay();
- if (delay > 0)
+ if (delay > 0) {
QTest::qWait(delay);
+ lastMouseTimestamp += delay;
+ }
QPoint pos;
QQuickItem *sgitem = qobject_cast<QQuickItem *>(item);
@@ -245,6 +247,7 @@ namespace QtQuickTest
stateKey &= static_cast<unsigned int>(Qt::KeyboardModifierMask);
QWheelEvent we(pos, window->mapToGlobal(pos), QPoint(0, 0), QPoint(xDelta, yDelta), buttons,
stateKey, Qt::NoScrollPhase, false);
+ we.setTimestamp(++lastMouseTimestamp);
QSpontaneKeyEvent::setSpontaneous(&we); // hmmmm
if (!qApp->notify(window, &we))
diff --git a/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp b/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp
index 3e75e39f86..c89fb86aec 100644
--- a/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp
+++ b/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp
@@ -324,3 +324,5 @@ bool QPacketProtocolPrivate::readFromDevice(char *buffer, qint64 size)
*/
QT_END_NAMESPACE
+
+#include "moc_qpacketprotocol_p.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp
index 3851cdc71f..c28bf0aaff 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp
@@ -56,3 +56,5 @@ QQmlDebugService *QQmlDebuggerServiceFactory::create(const QString &key)
}
QT_END_NAMESPACE
+
+#include "moc_qqmldebuggerservicefactory.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
index d435e82390..ec7f91d045 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
@@ -812,9 +812,9 @@ bool QQmlEngineDebugServiceImpl::setMethodBody(int objectId, const QString &meth
int lineNumber = 0;
QV4::ScopedFunctionObject oldMethod(scope, vmeMetaObject->vmeMethod(prop->coreIndex()));
- if (oldMethod && oldMethod->d()->function) {
- lineNumber = oldMethod->d()->function->compiledFunction->location.line;
- }
+ if (oldMethod && oldMethod->d()->function)
+ lineNumber = oldMethod->d()->function->compiledFunction->location.line();
+
QV4::ScopedValue v(scope, QQmlJavaScriptExpression::evalFunction(contextData, object, jsfunction, contextData->urlString(), lineNumber));
vmeMetaObject->setVmeMethod(prop->coreIndex(), v);
return true;
diff --git a/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp b/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp
index 012730902b..1638f18d2b 100644
--- a/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp
+++ b/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp
@@ -407,4 +407,6 @@ GlobalInspector::~GlobalInspector()
QT_END_NAMESPACE
+#include "moc_globalinspector.cpp"
+
#include <globalinspector.moc>
diff --git a/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.cpp b/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.cpp
index 4f6cb9364d..2de805d40d 100644
--- a/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.cpp
@@ -106,3 +106,5 @@ void QDebugMessageServiceImpl::synchronizeTime(const QElapsedTimer &otherTimer)
}
QT_END_NAMESPACE
+
+#include "moc_qdebugmessageservice.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservicefactory.cpp b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservicefactory.cpp
index c0b74c74ff..f3990f7e57 100644
--- a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservicefactory.cpp
+++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservicefactory.cpp
@@ -52,3 +52,5 @@ QQmlDebugService *QQmlNativeDebugServiceFactory::create(const QString &key)
}
QT_END_NAMESPACE
+
+#include "moc_qqmlnativedebugservicefactory.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp
index 1561777202..af255781bc 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp
@@ -66,3 +66,5 @@ void QQmlDebugTranslationServiceImpl::foundTranslationBinding(QQmlTranslationBin
}
QT_END_NAMESPACE
+
+#include "moc_qqmldebugtranslationservice.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp
index 8d8a8f18d2..a84ef0dc7b 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp
@@ -197,3 +197,5 @@ void QQmlPreviewFileLoader::clearCache()
}
QT_END_NAMESPACE
+
+#include "moc_qqmlpreviewfileloader.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp
index 8bb3b95e48..0e2521055c 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp
@@ -456,3 +456,5 @@ void QQmlPreviewHandler::tryCreateObject()
}
QT_END_NAMESPACE
+
+#include "moc_qqmlpreviewhandler.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp
index 2e6aaa5858..8e23749a47 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp
@@ -197,3 +197,5 @@ void QQmlPreviewServiceImpl::forwardFps(const QQmlPreviewHandler::FpsInfo &frame
}
QT_END_NAMESPACE
+
+#include "moc_qqmlpreviewservice.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp
index 6ff9805bbe..44d2cab526 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp
@@ -54,3 +54,5 @@ QQmlDebugService *QQmlPreviewServiceFactory::create(const QString &key)
}
QT_END_NAMESPACE
+
+#include "moc_qqmlpreviewservicefactory.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
index 4702bc3c33..7a1b19ab8b 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
+++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
@@ -159,3 +159,5 @@ void QQmlProfilerAdapter::receiveData(const QVector<QQmlProfilerData> &new_data,
}
QT_END_NAMESPACE
+
+#include "moc_qqmlprofileradapter.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp
index 79a1c82411..0abd54dfb1 100644
--- a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp
+++ b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp
@@ -175,3 +175,5 @@ void QQuickProfilerAdapter::receiveData(const QVector<QQuickProfilerData> &new_d
}
QT_END_NAMESPACE
+
+#include "moc_qquickprofileradapter.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_server/qmldbg_server.pro b/src/plugins/qmltooling/qmldbg_server/qmldbg_server.pro
index d7d24a4d39..4233388a11 100644
--- a/src/plugins/qmltooling/qmldbg_server/qmldbg_server.pro
+++ b/src/plugins/qmltooling/qmldbg_server/qmldbg_server.pro
@@ -2,7 +2,7 @@ TARGET = qmldbg_server
QT = qml-private packetprotocol-private
SOURCES += \
- $$PWD/qqmldebugserver.cpp
+ $$PWD/qqmldebugserverfactory.cpp
HEADERS += \
$$PWD/qqmldebugserverfactory.h
diff --git a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp b/src/plugins/qmltooling/qmldbg_server/qqmldebugserverfactory.cpp
index 4d68a4508b..19393dbe05 100644
--- a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp
+++ b/src/plugins/qmltooling/qmldbg_server/qqmldebugserverfactory.cpp
@@ -764,4 +764,4 @@ QQmlDebugConnector *QQmlDebugServerFactory::create(const QString &key)
QT_END_NAMESPACE
-#include "qqmldebugserver.moc"
+#include "qqmldebugserverfactory.moc"
diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp
index f3c12bce3f..e15771531a 100644
--- a/src/qml/animations/qabstractanimationjob.cpp
+++ b/src/qml/animations/qabstractanimationjob.cpp
@@ -65,6 +65,30 @@ QQmlAnimationTimer::QQmlAnimationTimer() :
{
}
+void QQmlAnimationTimer::unsetJobTimer(QAbstractAnimationJob *animation)
+{
+ if (!animation)
+ return;
+ if (animation->m_timer == this)
+ animation->m_timer = nullptr;
+
+ if (animation->isGroup()) {
+ QAnimationGroupJob *group = static_cast<QAnimationGroupJob *>(animation);
+ for (auto *child = group->firstChild(); child; child = child->nextSibling())
+ unsetJobTimer(child);
+ }
+}
+
+QQmlAnimationTimer::~QQmlAnimationTimer()
+{
+ for (const auto &animation : qAsConst(animations))
+ unsetJobTimer(animation);
+ for (const auto &animation : qAsConst(animationsToStart))
+ unsetJobTimer(animation);
+ for (const auto &animation : qAsConst(runningPauseAnimations))
+ unsetJobTimer(animation);
+}
+
QQmlAnimationTimer *QQmlAnimationTimer::instance(bool create)
{
QQmlAnimationTimer *inst;
@@ -216,6 +240,7 @@ void QQmlAnimationTimer::registerRunningAnimation(QAbstractAnimationJob *animati
void QQmlAnimationTimer::unregisterRunningAnimation(QAbstractAnimationJob *animation)
{
+ unsetJobTimer(animation);
if (animation->userControlDisabled())
return;
@@ -282,8 +307,10 @@ QAbstractAnimationJob::~QAbstractAnimationJob()
Q_ASSERT(m_state == Stopped);
if (oldState == Running) {
- Q_ASSERT(QQmlAnimationTimer::instance() == m_timer);
- m_timer->unregisterAnimation(this);
+ if (m_timer) {
+ Q_ASSERT(QQmlAnimationTimer::instance(false) == m_timer);
+ m_timer->unregisterAnimation(this);
+ }
}
Q_ASSERT(!m_hasRegisteredTimer);
}
@@ -308,8 +335,9 @@ void QAbstractAnimationJob::setState(QAbstractAnimationJob::State newState)
if (m_loopCount == 0)
return;
- if (!m_timer)
- m_timer = QQmlAnimationTimer::instance();
+ if (!m_timer) // don't create a timer just to stop the animation
+ m_timer = QQmlAnimationTimer::instance(newState != Stopped);
+ Q_ASSERT(m_timer || newState == Stopped);
State oldState = m_state;
int oldCurrentTime = m_currentTime;
@@ -337,8 +365,9 @@ void QAbstractAnimationJob::setState(QAbstractAnimationJob::State newState)
if (oldState == Running) {
if (newState == Paused && m_hasRegisteredTimer)
m_timer->ensureTimerUpdate();
- //the animation, is not running any more
- m_timer->unregisterAnimation(this);
+ // the animation is not running any more
+ if (m_timer)
+ m_timer->unregisterAnimation(this);
} else if (newState == Running) {
m_timer->registerAnimation(this, isTopLevel);
}
diff --git a/src/qml/animations/qabstractanimationjob_p.h b/src/qml/animations/qabstractanimationjob_p.h
index 9490070246..1010f0f392 100644
--- a/src/qml/animations/qabstractanimationjob_p.h
+++ b/src/qml/animations/qabstractanimationjob_p.h
@@ -207,6 +207,8 @@ private:
QQmlAnimationTimer();
public:
+ ~QQmlAnimationTimer(); // must be destructible by QThreadStorage
+
static QQmlAnimationTimer *instance();
static QQmlAnimationTimer *instance(bool create);
@@ -252,6 +254,7 @@ private:
void registerRunningAnimation(QAbstractAnimationJob *animation);
void unregisterRunningAnimation(QAbstractAnimationJob *animation);
+ void unsetJobTimer(QAbstractAnimationJob *animation);
int closestPauseAnimationTimeToFinish();
};
diff --git a/src/qml/common/common.pri b/src/qml/common/common.pri
index b333c0f6d9..b824812d27 100644
--- a/src/qml/common/common.pri
+++ b/src/qml/common/common.pri
@@ -1,8 +1,8 @@
!build_pass {
# Create a header containing a hash that describes this library. For a
# released version of Qt, we'll use the .tag file that is updated by git
- # archive with the commit hash. For unreleased versions, we'll ask git
- # describe. Note that it won't update unless qmake is run again, even if
+ # archive with the tree hash. For unreleased versions, we'll ask git
+ # rev-parse. Note that it won't update unless qmake is run again, even if
# the commit change also changed something in this library.
tagFile = $$PWD/../../.tag
tag =
@@ -10,7 +10,7 @@
tag = $$cat($$tagFile, singleline)
QMAKE_INTERNAL_INCLUDED_FILES += $$tagFile
}
- !equals(tag, "$${LITERAL_DOLLAR}Format:%H$${LITERAL_DOLLAR}") {
+ !equals(tag, "$${LITERAL_DOLLAR}Format:%T$${LITERAL_DOLLAR}") {
QML_COMPILE_HASH = $$tag
} else:exists($$PWD/../../.git) {
commit = $$system(git rev-parse HEAD)
diff --git a/src/qml/common/qqmljsfixedpoolarray_p.h b/src/qml/common/qqmljsfixedpoolarray_p.h
index b65b994d6c..15a8cd6878 100644
--- a/src/qml/common/qqmljsfixedpoolarray_p.h
+++ b/src/qml/common/qqmljsfixedpoolarray_p.h
@@ -86,7 +86,7 @@ public:
if (QTypeInfo<T>::isComplex) {
for (int i = 0; i < count; ++i)
new (data + i) T(vector.at(i));
- } else {
+ } else if (count) {
memcpy(data, static_cast<const void*>(vector.constData()), count * sizeof(T));
}
}
diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h
index be0ca3f477..413edead2a 100644
--- a/src/qml/common/qv4compileddata_p.h
+++ b/src/qml/common/qv4compileddata_p.h
@@ -120,18 +120,35 @@ struct TableIterator
struct Location
{
- union {
- quint32 _dummy;
- quint32_le_bitfield<0, 20> line;
- quint32_le_bitfield<20, 12> column;
- };
-
- Location() : _dummy(0) { }
+ Location() : m_data(QSpecialIntegerBitfieldZero) {}
+ Location(quint32 l, quint32 c) : Location()
+ {
+ m_data.set<LineField>(l);
+ m_data.set<ColumnField>(c);
+ Q_ASSERT(m_data.get<LineField>() == l);
+ Q_ASSERT(m_data.get<ColumnField>() == c);
+ }
inline bool operator<(const Location &other) const {
- return line < other.line ||
- (line == other.line && column < other.column);
+ return m_data.get<LineField>() < other.m_data.get<LineField>()
+ || (m_data.get<LineField>() == other.m_data.get<LineField>()
+ && m_data.get<ColumnField>() < other.m_data.get<ColumnField>());
}
+
+ void set(quint32 line, quint32 column)
+ {
+ m_data.set<LineField>(line);
+ m_data.set<ColumnField>(column);
+ }
+
+ quint32 line() const { return m_data.get<LineField>(); }
+ quint32 column() const { return m_data.get<ColumnField>(); }
+
+private:
+ using LineField = quint32_le_bitfield_member<0, 20>;
+ using ColumnField = quint32_le_bitfield_member<20, 12>;
+
+ quint32_le_bitfield_union<LineField, ColumnField> m_data;
};
static_assert(sizeof(Location) == 4, "Location structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
@@ -145,13 +162,21 @@ struct RegExp
RegExp_Unicode = 0x08,
RegExp_Sticky = 0x10
};
- union {
- quint32 _dummy;
- quint32_le_bitfield<0, 5> flags;
- quint32_le_bitfield<5, 27> stringIndex;
- };
- RegExp() : _dummy(0) { }
+ RegExp() : m_data(QSpecialIntegerBitfieldZero) {}
+ RegExp(quint32 flags, quint32 stringIndex) : RegExp()
+ {
+ m_data.set<FlagsField>(flags);
+ m_data.set<StringIndexField>(stringIndex);
+ }
+
+ quint32 flags() const { return m_data.get<FlagsField>(); }
+ quint32 stringIndex() const { return m_data.get<StringIndexField>(); }
+
+private:
+ using FlagsField = quint32_le_bitfield_member<0, 5>;
+ using StringIndexField = quint32_le_bitfield_member<5, 27>;
+ quint32_le_bitfield_union<FlagsField, StringIndexField> m_data;
};
static_assert(sizeof(RegExp) == 4, "RegExp structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
@@ -164,25 +189,40 @@ struct Lookup
Type_QmlContextPropertyGetter = 3
};
- union {
- quint32 _dummy;
- quint32_le_bitfield<0, 4> type_and_flags;
- quint32_le_bitfield<4, 28> nameIndex;
- };
+ quint32 typeAndFlags() const { return m_data.get<TypeAndFlagsField>(); }
+ quint32 nameIndex() const { return m_data.get<NameIndexField>(); }
- Lookup() : _dummy(0) { }
+ Lookup() : m_data(QSpecialIntegerBitfieldZero) {}
+ Lookup(Type type, quint32 nameIndex) : Lookup()
+ {
+ m_data.set<TypeAndFlagsField>(type);
+ m_data.set<NameIndexField>(nameIndex);
+ }
+
+private:
+ using TypeAndFlagsField = quint32_le_bitfield_member<0, 4>;
+ using NameIndexField = quint32_le_bitfield_member<4, 28>;
+ quint32_le_bitfield_union<TypeAndFlagsField, NameIndexField> m_data;
};
static_assert(sizeof(Lookup) == 4, "Lookup structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct JSClassMember
{
- union {
- quint32 _dummy;
- quint32_le_bitfield<0, 31> nameOffset;
- quint32_le_bitfield<31, 1> isAccessor;
- };
+ JSClassMember() : m_data(QSpecialIntegerBitfieldZero) {}
- JSClassMember() : _dummy(0) { }
+ void set(quint32 nameOffset, bool isAccessor)
+ {
+ m_data.set<NameOffsetField>(nameOffset);
+ m_data.set<IsAccessorField>(isAccessor ? 1 : 0);
+ }
+
+ quint32 nameOffset() const { return m_data.get<NameOffsetField>(); }
+ bool isAccessor() const { return m_data.get<IsAccessorField>() != 0; }
+
+private:
+ using NameOffsetField = quint32_le_bitfield_member<0, 31>;
+ using IsAccessorField = quint32_le_bitfield_member<31, 1>;
+ quint32_le_bitfield_union<NameOffsetField, IsAccessorField> m_data;
};
static_assert(sizeof(JSClassMember) == 4, "JSClassMember structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
@@ -265,11 +305,26 @@ enum class BuiltinType : unsigned int {
struct ParameterType
{
- union {
- quint32 _dummy;
- quint32_le_bitfield<0, 1> indexIsBuiltinType;
- quint32_le_bitfield<1, 31> typeNameIndexOrBuiltinType;
- };
+ void set(bool indexIsBuiltinType, quint32 typeNameIndexOrBuiltinType)
+ {
+ m_data.set<IndexIsBuiltinTypeField>(indexIsBuiltinType ? 1 : 0);
+ m_data.set<TypeNameIndexOrBuiltinTypeField>(typeNameIndexOrBuiltinType);
+ }
+
+ bool indexIsBuiltinType() const
+ {
+ return m_data.get<IndexIsBuiltinTypeField>() != 0;
+ }
+
+ quint32 typeNameIndexOrBuiltinType() const
+ {
+ return m_data.get<TypeNameIndexOrBuiltinTypeField>();
+ }
+
+private:
+ using IndexIsBuiltinTypeField = quint32_le_bitfield_member<0, 1>;
+ using TypeNameIndexOrBuiltinTypeField = quint32_le_bitfield_member<1, 31>;
+ quint32_le_bitfield_union<IndexIsBuiltinTypeField, TypeNameIndexOrBuiltinTypeField> m_data;
};
static_assert(sizeof(ParameterType) == 4, "ParameterType structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
@@ -448,7 +503,7 @@ struct Binding
{
quint32_le propertyNameIndex;
- enum ValueType : unsigned int {
+ enum Type : unsigned int {
Type_Invalid,
Type_Boolean,
Type_Number,
@@ -462,7 +517,7 @@ struct Binding
Type_GroupProperty
};
- enum Flags : unsigned int {
+ enum Flag : unsigned int {
IsSignalHandlerExpression = 0x1,
IsSignalHandlerObject = 0x2,
IsOnAssignment = 0x4,
@@ -474,11 +529,20 @@ struct Binding
IsCustomParserBinding = 0x100,
IsFunctionExpression = 0x200
};
+ Q_DECLARE_FLAGS(Flags, Flag);
+
+ using FlagsField = quint32_le_bitfield_member<0, 16>;
+ using TypeField = quint32_le_bitfield_member<16, 16>;
+ quint32_le_bitfield_union<FlagsField, TypeField> flagsAndType;
+
+ void clearFlags() { flagsAndType.set<FlagsField>(0); }
+ void setFlag(Flag flag) { flagsAndType.set<FlagsField>(flagsAndType.get<FlagsField>() | flag); }
+ bool hasFlag(Flag flag) const { return Flags(flagsAndType.get<FlagsField>()) & flag; }
+ Flags flags() const { return Flags(flagsAndType.get<FlagsField>()); }
+
+ void setType(Type type) { flagsAndType.set<TypeField>(type); }
+ Type type() const { return Type(flagsAndType.get<TypeField>()); }
- union {
- quint32_le_bitfield<0, 16> flags;
- quint32_le_bitfield<16, 16> type;
- };
union {
bool b;
quint32_le constantValueIndex;
@@ -492,23 +556,29 @@ struct Binding
Location location;
Location valueLocation;
+ bool hasSignalHandlerBindingFlag() const
+ {
+ const Flags bindingFlags = flags();
+ return (bindingFlags & IsSignalHandlerExpression || bindingFlags & IsSignalHandlerObject);
+ }
+
bool isValueBinding() const
{
- if (type == Type_AttachedProperty
- || type == Type_GroupProperty)
+ switch (type()) {
+ case Type_AttachedProperty:
+ case Type_GroupProperty:
return false;
- if (flags & IsSignalHandlerExpression
- || flags & IsSignalHandlerObject)
- return false;
- return true;
+ default:
+ return !hasSignalHandlerBindingFlag();
+ }
}
- bool isValueBindingNoAlias() const { return isValueBinding() && !(flags & IsBindingToAlias); }
- bool isValueBindingToAlias() const { return isValueBinding() && (flags & IsBindingToAlias); }
+ bool isValueBindingNoAlias() const { return isValueBinding() && !hasFlag(IsBindingToAlias); }
+ bool isValueBindingToAlias() const { return isValueBinding() && hasFlag(IsBindingToAlias); }
bool isSignalHandler() const
{
- if (flags & IsSignalHandlerExpression || flags & IsSignalHandlerObject) {
+ if (hasSignalHandlerBindingFlag()) {
Q_ASSERT(!isValueBinding());
Q_ASSERT(!isAttachedProperty());
Q_ASSERT(!isGroupProperty());
@@ -519,7 +589,7 @@ struct Binding
bool isAttachedProperty() const
{
- if (type == Type_AttachedProperty) {
+ if (type() == Type_AttachedProperty) {
Q_ASSERT(!isValueBinding());
Q_ASSERT(!isSignalHandler());
Q_ASSERT(!isGroupProperty());
@@ -530,7 +600,7 @@ struct Binding
bool isGroupProperty() const
{
- if (type == Type_GroupProperty) {
+ if (type() == Type_GroupProperty) {
Q_ASSERT(!isValueBinding());
Q_ASSERT(!isSignalHandler());
Q_ASSERT(!isAttachedProperty());
@@ -539,7 +609,7 @@ struct Binding
return false;
}
- bool isFunctionExpression() const { return (flags & IsFunctionExpression); }
+ bool isFunctionExpression() const { return hasFlag(IsFunctionExpression); }
//reverse of Lexer::singleEscape()
static QString escapedString(const QString &string)
@@ -584,16 +654,19 @@ struct Binding
return tmp;
}
- bool isTranslationBinding() const { return type == Type_Translation || type == Type_TranslationById; }
- bool evaluatesToString() const { return type == Type_String || isTranslationBinding(); }
+ bool isTranslationBinding() const
+ {
+ const Binding::Type bindingType = type();
+ return bindingType == Type_Translation || bindingType == Type_TranslationById;
+ }
+ bool evaluatesToString() const { return type() == Type_String || isTranslationBinding(); }
bool valueAsBoolean() const
{
- if (type == Type_Boolean)
+ if (type() == Type_Boolean)
return value.b;
return false;
}
-
};
static_assert(sizeof(Binding) == 24, "Binding structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
@@ -666,32 +739,57 @@ static_assert(sizeof(Signal) == 12, "Signal structure needs to have the expected
struct Property
{
- quint32_le nameIndex;
- union {
- quint32_le_bitfield<0, 28> builtinTypeOrTypeNameIndex;
- quint32_le_bitfield<28, 1> isRequired;
- quint32_le_bitfield<29, 1> isBuiltinType;
- quint32_le_bitfield<30, 1> isList;
- quint32_le_bitfield<31, 1> isReadOnly;
- };
+private:
+ using BuiltinTypeOrTypeNameIndexField = quint32_le_bitfield_member<0, 28>;
+ using IsRequiredField = quint32_le_bitfield_member<28, 1>;
+ using IsBuiltinTypeField = quint32_le_bitfield_member<29, 1>;
+ using IsListField = quint32_le_bitfield_member<30, 1>;
+ using IsReadOnlyField = quint32_le_bitfield_member<31, 1>;
+public:
+ quint32_le nameIndex;
+ quint32_le_bitfield_union<
+ BuiltinTypeOrTypeNameIndexField,
+ IsRequiredField,
+ IsBuiltinTypeField,
+ IsListField,
+ IsReadOnlyField> data;
Location location;
void setBuiltinType(BuiltinType t)
{
- builtinTypeOrTypeNameIndex = static_cast<quint32>(t);
- isBuiltinType = true;
+ data.set<BuiltinTypeOrTypeNameIndexField>(static_cast<quint32>(t));
+ data.set<IsBuiltinTypeField>(true);
}
+
BuiltinType builtinType() const {
- if (isBuiltinType)
- return static_cast<BuiltinType>(quint32(builtinTypeOrTypeNameIndex));
+ if (data.get<IsBuiltinTypeField>() != 0)
+ return BuiltinType(data.get<BuiltinTypeOrTypeNameIndexField>());
return BuiltinType::InvalidBuiltin;
}
+
void setCustomType(int nameIndex)
{
- builtinTypeOrTypeNameIndex = nameIndex;
- isBuiltinType = false;
+ data.set<BuiltinTypeOrTypeNameIndexField>(nameIndex);
+ data.set<IsBuiltinTypeField>(false);
}
+
+ int customType() const
+ {
+ return data.get<IsBuiltinTypeField>() ? -1 : data.get<BuiltinTypeOrTypeNameIndexField>();
+ }
+
+ bool isBuiltinType() const { return data.get<IsBuiltinTypeField>(); }
+ uint builtinTypeOrTypeNameIndex() const { return data.get<BuiltinTypeOrTypeNameIndexField>(); }
+
+ bool isList() const { return data.get<IsListField>(); }
+ void setIsList(bool isList) { data.set<IsListField>(isList); }
+
+ bool isRequired() const { return data.get<IsRequiredField>(); }
+ void setIsRequired(bool isRequired) { data.set<IsRequiredField>(isRequired); }
+
+ bool isReadOnly() const { return data.get<IsReadOnlyField>(); }
+ void setIsReadOnly(bool isReadOnly) { data.set<IsReadOnlyField>(isReadOnly); }
};
static_assert(sizeof(Property) == 12, "Property structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
@@ -702,20 +800,31 @@ struct RequiredPropertyExtraData {
static_assert (sizeof(RequiredPropertyExtraData) == 4, "RequiredPropertyExtraData structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Alias {
- enum Flags : unsigned int {
+private:
+ using NameIndexField = quint32_le_bitfield_member<0, 29>;
+ using FlagsField = quint32_le_bitfield_member<29, 3>;
+
+ // object id index (in QQmlContextData::idValues)
+ using TargetObjectIdField = quint32_le_bitfield_member<0, 31>;
+ using AliasToLocalAliasField = quint32_le_bitfield_member<31, 1>;
+
+public:
+
+ enum Flag : unsigned int {
IsReadOnly = 0x1,
Resolved = 0x2,
AliasPointsToPointerObject = 0x4
};
- union {
- quint32_le_bitfield<0, 29> nameIndex;
- quint32_le_bitfield<29, 3> flags;
- };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ quint32_le_bitfield_union<NameIndexField, FlagsField> nameIndexAndFlags;
+
union {
quint32_le idIndex; // string index
- quint32_le_bitfield<0, 31> targetObjectId; // object id index (in QQmlContextData::idValues)
- quint32_le_bitfield<31, 1> aliasToLocalAlias;
+ quint32_le_bitfield_union<TargetObjectIdField, AliasToLocalAliasField>
+ targetObjectIdAndAliasToLocalAlias;
};
+
union {
quint32_le propertyNameIndex; // string index
qint32_le encodedMetaPropertyIndex;
@@ -724,16 +833,67 @@ struct Alias {
Location location;
Location referenceLocation;
- bool isObjectAlias() const {
- Q_ASSERT(flags & Resolved);
+ bool hasFlag(Flag flag) const
+ {
+ return nameIndexAndFlags.get<FlagsField>() & flag;
+ }
+
+ void setFlag(Flag flag)
+ {
+ nameIndexAndFlags.set<FlagsField>(nameIndexAndFlags.get<FlagsField>() | flag);
+ }
+
+ void clearFlags()
+ {
+ nameIndexAndFlags.set<FlagsField>(0);
+ }
+
+ quint32 nameIndex() const
+ {
+ return nameIndexAndFlags.get<NameIndexField>();
+ }
+
+ void setNameIndex(quint32 nameIndex)
+ {
+ nameIndexAndFlags.set<NameIndexField>(nameIndex);
+ }
+
+ bool isObjectAlias() const
+ {
+ Q_ASSERT(hasFlag(Resolved));
return encodedMetaPropertyIndex == -1;
}
+
+ bool isAliasToLocalAlias() const
+ {
+ return targetObjectIdAndAliasToLocalAlias.get<AliasToLocalAliasField>();
+ }
+
+ void setIsAliasToLocalAlias(bool isAliasToLocalAlias)
+ {
+ targetObjectIdAndAliasToLocalAlias.set<AliasToLocalAliasField>(isAliasToLocalAlias);
+ }
+
+ quint32 targetObjectId() const
+ {
+ return targetObjectIdAndAliasToLocalAlias.get<TargetObjectIdField>();
+ }
+
+ void setTargetObjectId(quint32 targetObjectId)
+ {
+ targetObjectIdAndAliasToLocalAlias.set<TargetObjectIdField>(targetObjectId);
+ }
};
static_assert(sizeof(Alias) == 20, "Alias structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Object
{
- enum Flags : unsigned int {
+private:
+ using FlagsField = quint32_le_bitfield_member<0, 15>;
+ using DefaultPropertyIsAliasField = quint32_le_bitfield_member<15, 1>;
+ using IdField = quint32_le_bitfield_member<16, 16, qint32>;
+public:
+ enum Flag : unsigned int {
NoFlag = 0x0,
IsComponent = 0x1, // object was identified to be an explicit or implicit component boundary
HasDeferredBindings = 0x2, // any of the bindings are deferred
@@ -741,17 +901,15 @@ struct Object
IsInlineComponentRoot = 0x8,
InPartOfInlineComponent = 0x10
};
+ Q_DECLARE_FLAGS(Flags, Flag);
// Depending on the use, this may be the type name to instantiate before instantiating this
// object. For grouped properties the type name will be empty and for attached properties
// it will be the name of the attached type.
quint32_le inheritedTypeNameIndex;
quint32_le idNameIndex;
- union {
- quint32_le_bitfield<0, 15> flags;
- quint32_le_bitfield<15, 1> defaultPropertyIsAlias;
- qint32_le_bitfield<16, 16> id;
- };
+ quint32_le_bitfield_union<FlagsField, DefaultPropertyIsAliasField, IdField>
+ flagsAndDefaultPropertyIsAliasAndId;
qint32_le indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object
quint16_le nFunctions;
quint16_le nProperties;
@@ -780,6 +938,48 @@ struct Object
// InlineComponent[]
// RequiredPropertyExtraData[]
+ Flags flags() const
+ {
+ return Flags(flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>());
+ }
+
+ bool hasFlag(Flag flag) const
+ {
+ return flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>() & flag;
+ }
+
+ void setFlag(Flag flag)
+ {
+ flagsAndDefaultPropertyIsAliasAndId.set<FlagsField>(
+ flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>() | flag);
+ }
+
+ void setFlags(Flags flags)
+ {
+ flagsAndDefaultPropertyIsAliasAndId.set<FlagsField>(flags);
+ }
+
+ bool hasAliasAsDefaultProperty() const
+ {
+ return flagsAndDefaultPropertyIsAliasAndId.get<DefaultPropertyIsAliasField>();
+ }
+
+ void setHasAliasAsDefaultProperty(bool defaultAlias)
+ {
+ flagsAndDefaultPropertyIsAliasAndId.set<DefaultPropertyIsAliasField>(defaultAlias);
+ }
+
+ qint32 objectId() const
+ {
+ return flagsAndDefaultPropertyIsAliasAndId.get<IdField>();
+ }
+
+ void setObjectId(qint32 id)
+ {
+ flagsAndDefaultPropertyIsAliasAndId.set<IdField>(id);
+ }
+
+
static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent, int nInlineComponents, int nRequiredPropertyExtraData)
{
return ( sizeof(Object)
@@ -1129,8 +1329,8 @@ struct TypeReferenceMap : QHash<int, TypeReference>
auto prop = obj->propertiesBegin();
auto const propEnd = obj->propertiesEnd();
for ( ; prop != propEnd; ++prop) {
- if (!prop->isBuiltinType) {
- TypeReference &r = this->add(prop->builtinTypeOrTypeNameIndex, prop->location);
+ if (!prop->isBuiltinType()) {
+ TypeReference &r = this->add(prop->builtinTypeOrTypeNameIndex(), prop->location);
r.errorWhenNotFound = true;
}
}
@@ -1138,7 +1338,7 @@ struct TypeReferenceMap : QHash<int, TypeReference>
auto binding = obj->bindingsBegin();
auto const bindingEnd = obj->bindingsEnd();
for ( ; binding != bindingEnd; ++binding) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty)
+ if (binding->type() == QV4::CompiledData::Binding::Type_AttachedProperty)
this->add(binding->propertyNameIndex, binding->location);
}
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 2ad85ab910..36269691fc 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -76,7 +76,7 @@ void Object::simplifyRequiredProperties() {
for (auto it = this->propertiesBegin(); it != this->propertiesEnd(); ++it) {
auto requiredIt = required.find(it->nameIndex);
if (requiredIt != required.end()) {
- it->isRequired = true;
+ it->setIsRequired(true);
required.erase(requiredIt);
}
}
@@ -106,20 +106,18 @@ bool Parameter::init(QV4::CompiledData::Parameter *param, const QV4::Compiler::J
bool Parameter::initType(QV4::CompiledData::ParameterType *paramType, const QV4::Compiler::JSUnitGenerator *stringGenerator, int typeNameIndex)
{
- paramType->indexIsBuiltinType = false;
- paramType->typeNameIndexOrBuiltinType = 0;
const QString typeName = stringGenerator->stringForIndex(typeNameIndex);
auto builtinType = stringToBuiltinType(typeName);
if (builtinType == QV4::CompiledData::BuiltinType::InvalidBuiltin) {
- if (typeName.isEmpty() || !typeName.at(0).isUpper())
+ if (typeName.isEmpty() || !typeName.at(0).isUpper()) {
+ paramType->set(false, 0);
return false;
- paramType->indexIsBuiltinType = false;
- paramType->typeNameIndexOrBuiltinType = typeNameIndex;
+ }
Q_ASSERT(quint32(typeNameIndex) < (1u << 31));
+ paramType->set(false, typeNameIndex);
} else {
- paramType->indexIsBuiltinType = true;
- paramType->typeNameIndexOrBuiltinType = static_cast<quint32>(builtinType);
Q_ASSERT(quint32(builtinType) < (1u << 31));
+ paramType->set(true, static_cast<quint32>(builtinType));
}
return true;
}
@@ -173,9 +171,7 @@ void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, cons
{
inheritedTypeNameIndex = typeNameIndex;
- location.line = loc.startLine;
- location.column = loc.startColumn;
-
+ location.set(loc.startLine, loc.startColumn);
idNameIndex = idIndex;
id = -1;
indexOfDefaultPropertyOrAlias = -1;
@@ -198,8 +194,8 @@ QString IRBuilder::sanityCheckFunctionNames(Object *obj, const QSet<QString> &il
QSet<int> functionNames;
for (auto functionit = obj->functionsBegin(); functionit != obj->functionsEnd(); ++functionit) {
Function *f = functionit.ptr;
- errorLocation->startLine = f->location.line;
- errorLocation->startColumn = f->location.column;
+ errorLocation->startLine = f->location.line();
+ errorLocation->startColumn = f->location.column();
if (functionNames.contains(f->nameIndex))
return tr("Duplicate method name");
functionNames.insert(f->nameIndex);
@@ -280,7 +276,7 @@ QString Object::appendAlias(Alias *alias, const QString &aliasName, bool isDefau
target = this;
auto aliasWithSameName = std::find_if(target->aliases->begin(), target->aliases->end(), [&alias](const Alias &targetAlias){
- return targetAlias.nameIndex == alias->nameIndex;
+ return targetAlias.nameIndex() == alias->nameIndex();
});
if (aliasWithSameName != target->aliases->end())
return tr("Duplicate alias name");
@@ -323,13 +319,17 @@ void Object::appendRequiredPropertyExtraData(RequiredPropertyExtraData *extraDat
QString Object::appendBinding(Binding *b, bool isListBinding)
{
const bool bindingToDefaultProperty = (b->propertyNameIndex == quint32(0));
- if (!isListBinding && !bindingToDefaultProperty
- && b->type != QV4::CompiledData::Binding::Type_GroupProperty
- && b->type != QV4::CompiledData::Binding::Type_AttachedProperty
- && !(b->flags & QV4::CompiledData::Binding::IsOnAssignment)) {
+ if (!isListBinding
+ && !bindingToDefaultProperty
+ && b->type() != QV4::CompiledData::Binding::Type_GroupProperty
+ && b->type() != QV4::CompiledData::Binding::Type_AttachedProperty
+ && !b->hasFlag(QV4::CompiledData::Binding::IsOnAssignment)) {
Binding *existing = findBinding(b->propertyNameIndex);
- if (existing && existing->isValueBinding() == b->isValueBinding() && !(existing->flags & QV4::CompiledData::Binding::IsOnAssignment))
+ if (existing
+ && existing->isValueBinding() == b->isValueBinding()
+ && !existing->hasFlag(QV4::CompiledData::Binding::IsOnAssignment)) {
return tr("Property value set multiple times");
+ }
}
if (bindingToDefaultProperty)
insertSorted(b);
@@ -397,8 +397,7 @@ void ScriptDirectivesCollector::importFile(const QString &jsfile, const QString
import->type = QV4::CompiledData::Import::ImportScript;
import->uriIndex = jsGenerator->registerString(jsfile);
import->qualifierIndex = jsGenerator->registerString(module);
- import->location.line = lineNumber;
- import->location.column = column;
+ import->location.set(lineNumber, column);
document->imports << import;
}
@@ -413,8 +412,7 @@ void ScriptDirectivesCollector::importModule(const QString &uri, const QString &
import->majorVersion = vmaj;
import->minorVersion = vmin;
import->qualifierIndex = jsGenerator->registerString(module);
- import->location.line = lineNumber;
- import->location.column = column;
+ import->location.set(lineNumber, column);
document->imports << import;
}
@@ -575,8 +573,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiInlineComponent *ast)
inlineComponent->nameIndex = registerString(ast->name.toString());
inlineComponent->objectIndex = idx;
auto location = ast->firstSourceLocation();
- inlineComponent->location.line = location.startLine;
- inlineComponent->location.column = location.startColumn;
+ inlineComponent->location.set(location.startLine, location.startColumn);
_object->appendInlineComponent(inlineComponent);
return false;
}
@@ -772,8 +769,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiImport *node)
import->minorVersion = -1;
}
- import->location.line = node->importToken.startLine;
- import->location.column = node->importToken.startColumn;
+ import->location.set(node->importToken.startLine, node->importToken.startColumn);
import->uriIndex = registerString(uri);
@@ -801,8 +797,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPragma *node)
return false;
}
- pragma->location.line = node->pragmaToken.startLine;
- pragma->location.column = node->pragmaToken.startColumn;
+ pragma->location.set(node->pragmaToken.startLine, node->pragmaToken.startColumn);
_pragmas.append(pragma);
return false;
@@ -835,8 +830,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiEnumDeclaration *node)
if (enumName.at(0).isLower())
COMPILE_EXCEPTION(node->enumToken, tr("Scoped enum names must begin with an upper case letter"));
- enumeration->location.line = node->enumToken.startLine;
- enumeration->location.column = node->enumToken.startColumn;
+ enumeration->location.set(node->enumToken.startLine, node->enumToken.startColumn);
enumeration->enumValues = New<PoolList<EnumValue>>();
@@ -855,8 +849,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiEnumDeclaration *node)
COMPILE_EXCEPTION(e->valueToken, tr("Enum value out of range"));
enumValue->value = e->value;
- enumValue->location.line = e->memberToken.startLine;
- enumValue->location.column = e->memberToken.startColumn;
+ enumValue->location.set(e->memberToken.startLine, e->memberToken.startColumn);
enumeration->enumValues->append(enumValue);
e = e->next;
@@ -880,8 +873,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
signal->nameIndex = registerString(signalName);
QQmlJS::SourceLocation loc = node->typeToken;
- signal->location.line = loc.startLine;
- signal->location.column = loc.startColumn;
+ signal->location.set(loc.startLine, loc.startColumn);
signal->parameters = New<PoolList<Parameter> >();
@@ -930,8 +922,8 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
const QStringRef &name = node->name;
Property *property = New<Property>();
- property->isReadOnly = node->isReadonlyMember;
- property->isRequired = node->isRequired;
+ property->setIsReadOnly(node->isReadonlyMember);
+ property->setIsRequired(node->isRequired);
QV4::CompiledData::BuiltinType builtinPropertyType = Parameter::stringToBuiltinType(memberType);
bool typeFound = builtinPropertyType != QV4::CompiledData::BuiltinType::InvalidBuiltin;
@@ -943,7 +935,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
property->setCustomType(registerString(memberType));
if (typeModifier == QLatin1String("list")) {
- property->isList = true;
+ property->setIsList(true);
} else if (!typeModifier.isEmpty()) {
recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Invalid property type modifier"));
return false;
@@ -963,8 +955,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
property->nameIndex = registerString(propName);
QQmlJS::SourceLocation loc = node->firstSourceLocation();
- property->location.line = loc.startLine;
- property->location.column = loc.startColumn;
+ property->location.set(loc.startLine, loc.startColumn);
QQmlJS::SourceLocation errorLocation;
QString error;
@@ -1008,8 +999,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node)
Function *f = New<Function>();
QQmlJS::SourceLocation loc = funDecl->identifierToken;
- f->location.line = loc.startLine;
- f->location.column = loc.startColumn;
+ f->location.set(loc.startLine, loc.startColumn);
f->index = index;
f->nameIndex = registerString(funDecl->name.toString());
@@ -1089,26 +1079,25 @@ QStringRef IRBuilder::textRefAt(const QQmlJS::SourceLocation &first, const QQmlJ
void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement, QQmlJS::AST::Node *parentNode)
{
QQmlJS::SourceLocation loc = statement->firstSourceLocation();
- binding->valueLocation.line = loc.startLine;
- binding->valueLocation.column = loc.startColumn;
- binding->type = QV4::CompiledData::Binding::Type_Invalid;
- if (_propertyDeclaration && _propertyDeclaration->isReadOnly)
- binding->flags |= QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration;
+ binding->valueLocation.set(loc.startLine, loc.startColumn);
+ binding->setType(QV4::CompiledData::Binding::Type_Invalid);
+ if (_propertyDeclaration && _propertyDeclaration->isReadOnly())
+ binding->setFlag(QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration);
QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement);
if (exprStmt) {
QQmlJS::AST::ExpressionNode * const expr = exprStmt->expression;
if (QQmlJS::AST::StringLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(expr)) {
- binding->type = QV4::CompiledData::Binding::Type_String;
+ binding->setType(QV4::CompiledData::Binding::Type_String);
binding->stringIndex = registerString(lit->value.toString());
} else if (expr->kind == QQmlJS::AST::Node::Kind_TrueLiteral) {
- binding->type = QV4::CompiledData::Binding::Type_Boolean;
+ binding->setType(QV4::CompiledData::Binding::Type_Boolean);
binding->value.b = true;
} else if (expr->kind == QQmlJS::AST::Node::Kind_FalseLiteral) {
- binding->type = QV4::CompiledData::Binding::Type_Boolean;
+ binding->setType(QV4::CompiledData::Binding::Type_Boolean);
binding->value.b = false;
} else if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(expr)) {
- binding->type = QV4::CompiledData::Binding::Type_Number;
+ binding->setType(QV4::CompiledData::Binding::Type_Number);
binding->value.constantValueIndex = jsGenerator->registerConstant(QV4::Encode(lit->value));
} else if (QQmlJS::AST::CallExpression *call = QQmlJS::AST::cast<QQmlJS::AST::CallExpression *>(expr)) {
if (QQmlJS::AST::IdentifierExpression *base = QQmlJS::AST::cast<QQmlJS::AST::IdentifierExpression *>(call->base)) {
@@ -1117,21 +1106,21 @@ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST
// below.
}
} else if (QQmlJS::AST::cast<QQmlJS::AST::FunctionExpression *>(expr)) {
- binding->flags |= QV4::CompiledData::Binding::IsFunctionExpression;
+ binding->setFlag(QV4::CompiledData::Binding::IsFunctionExpression);
} else if (QQmlJS::AST::UnaryMinusExpression *unaryMinus = QQmlJS::AST::cast<QQmlJS::AST::UnaryMinusExpression *>(expr)) {
if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(unaryMinus->expression)) {
- binding->type = QV4::CompiledData::Binding::Type_Number;
+ binding->setType(QV4::CompiledData::Binding::Type_Number);
binding->value.constantValueIndex = jsGenerator->registerConstant(QV4::Encode(-lit->value));
}
} else if (QQmlJS::AST::cast<QQmlJS::AST::NullExpression *>(expr)) {
- binding->type = QV4::CompiledData::Binding::Type_Null;
+ binding->setType(QV4::CompiledData::Binding::Type_Null);
binding->value.nullMarker = 0;
}
}
// Do binding instead
- if (binding->type == QV4::CompiledData::Binding::Type_Invalid) {
- binding->type = QV4::CompiledData::Binding::Type_Script;
+ if (binding->type() == QV4::CompiledData::Binding::Type_Invalid) {
+ binding->setType(QV4::CompiledData::Binding::Type_Script);
CompiledFunctionOrExpression *expr = New<CompiledFunctionOrExpression>();
expr->node = statement;
@@ -1187,7 +1176,7 @@ void IRBuilder::tryGeneratingTranslationBinding(const QStringRef &base, AST::Arg
if (args)
return; // too many arguments, stop
- binding->type = QV4::CompiledData::Binding::Type_Translation;
+ binding->setType(QV4::CompiledData::Binding::Type_Translation);
binding->value.translationDataIndex = jsGenerator->registerTranslation(translationData);
} else if (base == QLatin1String("qsTrId")) {
QV4::CompiledData::TranslationData translationData;
@@ -1220,7 +1209,7 @@ void IRBuilder::tryGeneratingTranslationBinding(const QStringRef &base, AST::Arg
if (args)
return; // too many arguments, stop
- binding->type = QV4::CompiledData::Binding::Type_TranslationById;
+ binding->setType(QV4::CompiledData::Binding::Type_TranslationById);
binding->value.translationDataIndex = jsGenerator->registerTranslation(translationData);
} else if (base == QLatin1String("QT_TR_NOOP") || base == QLatin1String("QT_TRID_NOOP")) {
if (!args || !args->expression)
@@ -1237,7 +1226,7 @@ void IRBuilder::tryGeneratingTranslationBinding(const QStringRef &base, AST::Arg
if (args)
return; // too many arguments, stop
- binding->type = QV4::CompiledData::Binding::Type_String;
+ binding->setType(QV4::CompiledData::Binding::Type_String);
binding->stringIndex = jsGenerator->registerString(str.toString());
} else if (base == QLatin1String("QT_TRANSLATE_NOOP")) {
if (!args || !args->expression)
@@ -1258,7 +1247,7 @@ void IRBuilder::tryGeneratingTranslationBinding(const QStringRef &base, AST::Arg
if (args)
return; // too many arguments, stop
- binding->type = QV4::CompiledData::Binding::Type_String;
+ binding->setType(QV4::CompiledData::Binding::Type_String);
binding->stringIndex = jsGenerator->registerString(str.toString());
}
}
@@ -1295,9 +1284,8 @@ void IRBuilder::appendBinding(const QQmlJS::SourceLocation &qualifiedNameLocatio
Binding *binding = New<Binding>();
binding->propertyNameIndex = propertyNameIndex;
binding->offset = nameLocation.offset;
- binding->location.line = nameLocation.startLine;
- binding->location.column = nameLocation.startColumn;
- binding->flags = 0;
+ binding->location.set(nameLocation.startLine, nameLocation.startColumn);
+ binding->clearFlags();
setBindingValue(binding, value, parentNode);
QString error = bindingsTarget()->appendBinding(binding, /*isListBinding*/false);
if (!error.isEmpty()) {
@@ -1315,27 +1303,26 @@ void IRBuilder::appendBinding(const QQmlJS::SourceLocation &qualifiedNameLocatio
Binding *binding = New<Binding>();
binding->propertyNameIndex = propertyNameIndex;
binding->offset = nameLocation.offset;
- binding->location.line = nameLocation.startLine;
- binding->location.column = nameLocation.startColumn;
+ binding->location.set(nameLocation.startLine, nameLocation.startColumn);
const Object *obj = _objects.at(objectIndex);
binding->valueLocation = obj->location;
- binding->flags = 0;
+ binding->clearFlags();
- if (_propertyDeclaration && _propertyDeclaration->isReadOnly)
- binding->flags |= QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration;
+ if (_propertyDeclaration && _propertyDeclaration->isReadOnly())
+ binding->setFlag(QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration);
// No type name on the initializer means it must be a group property
if (_objects.at(objectIndex)->inheritedTypeNameIndex == emptyStringIndex)
- binding->type = QV4::CompiledData::Binding::Type_GroupProperty;
+ binding->setType(Binding::Type_GroupProperty);
else
- binding->type = QV4::CompiledData::Binding::Type_Object;
+ binding->setType(Binding::Type_Object);
if (isOnAssignment)
- binding->flags |= QV4::CompiledData::Binding::IsOnAssignment;
+ binding->setFlag(Binding::IsOnAssignment);
if (isListItem)
- binding->flags |= QV4::CompiledData::Binding::IsListItem;
+ binding->setFlag(Binding::IsListItem);
binding->value.objectIndex = objectIndex;
QString error = bindingsTarget()->appendBinding(binding, isListItem);
@@ -1347,16 +1334,15 @@ void IRBuilder::appendBinding(const QQmlJS::SourceLocation &qualifiedNameLocatio
bool IRBuilder::appendAlias(QQmlJS::AST::UiPublicMember *node)
{
Alias *alias = New<Alias>();
- alias->flags = 0;
+ alias->clearFlags();
if (node->isReadonlyMember)
- alias->flags |= QV4::CompiledData::Alias::IsReadOnly;
+ alias->setFlag(QV4::CompiledData::Alias::IsReadOnly);
const QString propName = node->name.toString();
- alias->nameIndex = registerString(propName);
+ alias->setNameIndex(registerString(propName));
QQmlJS::SourceLocation loc = node->firstSourceLocation();
- alias->location.line = loc.startLine;
- alias->location.column = loc.startColumn;
+ alias->location.set(loc.startLine, loc.startColumn);
alias->propertyNameIndex = emptyStringIndex;
@@ -1370,8 +1356,7 @@ bool IRBuilder::appendAlias(QQmlJS::AST::UiPublicMember *node)
rhsLoc = node->statement->firstSourceLocation();
else
rhsLoc = node->semicolonToken;
- alias->referenceLocation.line = rhsLoc.startLine;
- alias->referenceLocation.column = rhsLoc.startColumn;
+ alias->referenceLocation.set(rhsLoc.startLine, rhsLoc.startColumn);
QStringList aliasReference;
@@ -1466,8 +1451,7 @@ bool IRBuilder::setId(const QQmlJS::SourceLocation &idLocation, QQmlJS::AST::Sta
COMPILE_EXCEPTION(idLocation, tr("Property value set multiple times"));
_object->idNameIndex = registerString(idQString);
- _object->locationOfIdProperty.line = idLocation.startLine;
- _object->locationOfIdProperty.column = idLocation.startColumn;
+ _object->locationOfIdProperty.set(idLocation.startLine, idLocation.startColumn);
return true;
}
@@ -1513,19 +1497,23 @@ bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, O
binding = New<Binding>();
binding->propertyNameIndex = propertyNameIndex;
binding->offset = qualifiedIdElement->identifierToken.offset;
- binding->location.line = qualifiedIdElement->identifierToken.startLine;
- binding->location.column = qualifiedIdElement->identifierToken.startColumn;
- binding->valueLocation.line = qualifiedIdElement->next->identifierToken.startLine;
- binding->valueLocation.column = qualifiedIdElement->next->identifierToken.startColumn;
- binding->flags = 0;
+ binding->location.set(qualifiedIdElement->identifierToken.startLine,
+ qualifiedIdElement->identifierToken.startColumn);
+ binding->valueLocation.set(qualifiedIdElement->next->identifierToken.startLine,
+ qualifiedIdElement->next->identifierToken.startColumn);
+ binding->location.set(qualifiedIdElement->identifierToken.startLine,
+ qualifiedIdElement->identifierToken.startColumn);
+ binding->valueLocation.set(qualifiedIdElement->next->identifierToken.startLine,
+ qualifiedIdElement->next->identifierToken.startColumn);
+ binding->clearFlags();
if (onAssignment)
- binding->flags |= QV4::CompiledData::Binding::IsOnAssignment;
+ binding->setFlag(QV4::CompiledData::Binding::IsOnAssignment);
if (isAttachedProperty)
- binding->type = QV4::CompiledData::Binding::Type_AttachedProperty;
+ binding->setType(QV4::CompiledData::Binding::Type_AttachedProperty);
else
- binding->type = QV4::CompiledData::Binding::Type_GroupProperty;
+ binding->setType(QV4::CompiledData::Binding::Type_GroupProperty);
int objIndex = 0;
if (!defineQMLObject(&objIndex, nullptr, QQmlJS::SourceLocation(), nullptr, nullptr))
@@ -1586,7 +1574,7 @@ bool IRBuilder::isStatementNodeScript(QQmlJS::AST::Statement *statement)
bool IRBuilder::isRedundantNullInitializerForPropertyDeclaration(Property *property, QQmlJS::AST::Statement *statement)
{
- if (property->isBuiltinType || property->isList)
+ if (property->isBuiltinType() || property->isList())
return false;
QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement);
if (!exprStmt)
@@ -1684,10 +1672,10 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
QV4::CompiledData::Object *objectToWrite = reinterpret_cast<QV4::CompiledData::Object*>(objectPtr);
objectToWrite->inheritedTypeNameIndex = o->inheritedTypeNameIndex;
objectToWrite->indexOfDefaultPropertyOrAlias = o->indexOfDefaultPropertyOrAlias;
- objectToWrite->defaultPropertyIsAlias = o->defaultPropertyIsAlias;
- objectToWrite->flags = o->flags;
+ objectToWrite->setHasAliasAsDefaultProperty(o->defaultPropertyIsAlias);
+ objectToWrite->setFlags(QV4::CompiledData::Object::Flags(o->flags));
objectToWrite->idNameIndex = o->idNameIndex;
- objectToWrite->id = o->id;
+ objectToWrite->setObjectId(o->id);
objectToWrite->location = o->location;
objectToWrite->locationOfIdProperty = o->locationOfIdProperty;
@@ -1862,7 +1850,7 @@ char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, Binding
continue;
QV4::CompiledData::Binding *bindingToWrite = reinterpret_cast<QV4::CompiledData::Binding*>(bindingPtr);
*bindingToWrite = *b;
- if (b->type == QV4::CompiledData::Binding::Type_Script)
+ if (b->type() == QV4::CompiledData::Binding::Type_Script)
bindingToWrite->value.compiledScriptIndex = o->runtimeFunctionIndices.at(b->value.compiledScriptIndex);
bindingPtr += sizeof(QV4::CompiledData::Binding);
}
@@ -1901,6 +1889,12 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
scan.enterEnvironment(f.parentNode, QV4::Compiler::ContextType::Binding, qmlName(f));
}
+ /* We do not want to visit the whole function, as we already called enterQmlFunction
+ However, there might be a function defined as a default argument of the function.
+ That needs to be considered, too, so we call handleTopLevelFunctionFormals to
+ deal with them.
+ */
+ scan.handleTopLevelFunctionFormals(function);
scan(function ? function->body : f.node);
scan.leaveEnvironment();
}
@@ -1966,7 +1960,7 @@ bool JSCodeGen::compileComponent(int contextObject)
if (obj->flags & QV4::CompiledData::Object::IsComponent && !obj->isInlineComponent) {
Q_ASSERT(obj->bindingCount() == 1);
const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
+ Q_ASSERT(componentBinding->type() == QV4::CompiledData::Binding::Type_Object);
contextObject = componentBinding->value.objectIndex;
}
for (auto it = obj->inlineComponentsBegin(); it != obj->inlineComponentsEnd(); ++it)
@@ -1994,11 +1988,12 @@ bool JSCodeGen::compileJavaScriptCodeInObjectsRecursively(int objectIndex, int s
}
for (const QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
- if (binding->type < QV4::CompiledData::Binding::Type_Object)
+ const Binding::Type bindingType = binding->type();
+ if (bindingType < QV4::CompiledData::Binding::Type_Object)
continue;
int target = binding->value.objectIndex;
- int scope = binding->type == QV4::CompiledData::Binding::Type_Object ? target : scopeObjectIndex;
+ int scope = bindingType == QV4::CompiledData::Binding::Type_Object ? target : scopeObjectIndex;
if (!compileJavaScriptCodeInObjectsRecursively(binding->value.objectIndex, scope))
return false;
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 9629a73199..8996777289 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -394,6 +394,10 @@ public:
int namedObjectsInComponentCount() const { return namedObjectsInComponent.size(); }
const quint32 *namedObjectsInComponentTable() const { return namedObjectsInComponent.begin(); }
+ bool hasFlag(QV4::CompiledData::Object::Flag flag) const { return flags & flag; }
+ qint32 objectId() const { return id; }
+ bool hasAliasAsDefaultProperty() const { return defaultPropertyIsAlias; }
+
private:
friend struct ::QQmlIRLoader;
diff --git a/src/qml/compiler/qv4bytecodegenerator_p.h b/src/qml/compiler/qv4bytecodegenerator_p.h
index 1895a34a68..5244c443c4 100644
--- a/src/qml/compiler/qv4bytecodegenerator_p.h
+++ b/src/qml/compiler/qv4bytecodegenerator_p.h
@@ -186,13 +186,13 @@ QT_WARNING_POP
Q_REQUIRED_RESULT Jump jumpNotUndefined()
{
- Instruction::JumpNotUndefined data;
+ Instruction::JumpNotUndefined data{};
return addJumpInstruction(data);
}
Q_REQUIRED_RESULT Jump jumpNoException()
{
- Instruction::JumpNoException data;
+ Instruction::JumpNoException data{};
return addJumpInstruction(data);
}
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 4588690307..5a0dc11fbf 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -2927,6 +2927,17 @@ bool Codegen::visit(YieldExpression *ast)
return false;
}
+ auto innerMostCurentFunctionContext = _context;
+ while (innerMostCurentFunctionContext && innerMostCurentFunctionContext->contextType != ContextType::Function)
+ innerMostCurentFunctionContext = innerMostCurentFunctionContext->parent;
+
+ Q_ASSERT(innerMostCurentFunctionContext); // yield outside function would have been rejected by parser
+
+ if (!innerMostCurentFunctionContext->isGenerator) {
+ throwSyntaxError(ast->firstSourceLocation(), QLatin1String("Yield is only valid in generator functions"));
+ return false;
+ }
+
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference expr = ast->expression ? expression(ast->expression) : Reference::fromConst(this, Encode::undefined());
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 14cf0a0c8f..18e19cf01c 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -160,10 +160,7 @@ int QV4::Compiler::JSUnitGenerator::registerGetterLookup(const QString &name)
int QV4::Compiler::JSUnitGenerator::registerGetterLookup(int nameIndex)
{
- CompiledData::Lookup l;
- l.type_and_flags = CompiledData::Lookup::Type_Getter;
- l.nameIndex = nameIndex;
- lookups << l;
+ lookups << CompiledData::Lookup(CompiledData::Lookup::Type_Getter, nameIndex);
return lookups.size() - 1;
}
@@ -174,49 +171,37 @@ int QV4::Compiler::JSUnitGenerator::registerSetterLookup(const QString &name)
int QV4::Compiler::JSUnitGenerator::registerSetterLookup(int nameIndex)
{
- CompiledData::Lookup l;
- l.type_and_flags = CompiledData::Lookup::Type_Setter;
- l.nameIndex = nameIndex;
- lookups << l;
+ lookups << CompiledData::Lookup(CompiledData::Lookup::Type_Setter, nameIndex);
return lookups.size() - 1;
}
int QV4::Compiler::JSUnitGenerator::registerGlobalGetterLookup(int nameIndex)
{
- CompiledData::Lookup l;
- l.type_and_flags = CompiledData::Lookup::Type_GlobalGetter;
- l.nameIndex = nameIndex;
- lookups << l;
+ lookups << CompiledData::Lookup(CompiledData::Lookup::Type_GlobalGetter, nameIndex);
return lookups.size() - 1;
}
int QV4::Compiler::JSUnitGenerator::registerQmlContextPropertyGetterLookup(int nameIndex)
{
- CompiledData::Lookup l;
- l.type_and_flags = CompiledData::Lookup::Type_QmlContextPropertyGetter;
- l.nameIndex = nameIndex;
- lookups << l;
+ lookups << CompiledData::Lookup(CompiledData::Lookup::Type_QmlContextPropertyGetter, nameIndex);
return lookups.size() - 1;
}
int QV4::Compiler::JSUnitGenerator::registerRegExp(QQmlJS::AST::RegExpLiteral *regexp)
{
- CompiledData::RegExp re;
- re.stringIndex = registerString(regexp->pattern.toString());
-
- re.flags = 0;
+ quint32 flags = 0;
if (regexp->flags & QQmlJS::Lexer::RegExp_Global)
- re.flags |= CompiledData::RegExp::RegExp_Global;
+ flags |= CompiledData::RegExp::RegExp_Global;
if (regexp->flags & QQmlJS::Lexer::RegExp_IgnoreCase)
- re.flags |= CompiledData::RegExp::RegExp_IgnoreCase;
+ flags |= CompiledData::RegExp::RegExp_IgnoreCase;
if (regexp->flags & QQmlJS::Lexer::RegExp_Multiline)
- re.flags |= CompiledData::RegExp::RegExp_Multiline;
+ flags |= CompiledData::RegExp::RegExp_Multiline;
if (regexp->flags & QQmlJS::Lexer::RegExp_Unicode)
- re.flags |= CompiledData::RegExp::RegExp_Unicode;
+ flags |= CompiledData::RegExp::RegExp_Unicode;
if (regexp->flags & QQmlJS::Lexer::RegExp_Sticky)
- re.flags |= CompiledData::RegExp::RegExp_Sticky;
+ flags |= CompiledData::RegExp::RegExp_Sticky;
- regexps.append(re);
+ regexps.append(CompiledData::RegExp(flags, registerString(regexp->pattern.toString())));
return regexps.size() - 1;
}
@@ -249,8 +234,7 @@ int QV4::Compiler::JSUnitGenerator::registerJSClass(const QStringList &members)
CompiledData::JSClassMember *member = reinterpret_cast<CompiledData::JSClassMember*>(jsClass + 1);
for (const auto &name : members) {
- member->nameOffset = registerString(name);
- member->isAccessor = false;
+ member->set(registerString(name), false);
++member;
}
@@ -468,8 +452,7 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
currentOffset += function->nLabelInfos * sizeof(quint32);
}
- function->location.line = irFunction->line;
- function->location.column = irFunction->column;
+ function->location.set(irFunction->line, irFunction->column);
function->codeOffset = currentOffset;
function->codeSize = irFunction->code.size();
diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp
index a1ddee8234..bd3a456c36 100644
--- a/src/qml/compiler/qv4compilerscanfunctions.cpp
+++ b/src/qml/compiler/qv4compilerscanfunctions.cpp
@@ -57,10 +57,7 @@ using namespace QQmlJS::AST;
static CompiledData::Location location(const QQmlJS::SourceLocation &astLocation)
{
- CompiledData::Location target;
- target.line = astLocation.startLine;
- target.column = astLocation.startColumn;
- return target;
+ return CompiledData::Location(astLocation.startLine, astLocation.startColumn);
}
diff --git a/src/qml/compiler/qv4compilerscanfunctions_p.h b/src/qml/compiler/qv4compilerscanfunctions_p.h
index e39aa2454e..56172e2ea5 100644
--- a/src/qml/compiler/qv4compilerscanfunctions_p.h
+++ b/src/qml/compiler/qv4compilerscanfunctions_p.h
@@ -83,6 +83,13 @@ public:
ScanFunctions(Codegen *cg, const QString &sourceCode, ContextType defaultProgramType);
void operator()(QQmlJS::AST::Node *node);
+ // see comment at its call site in generateJSCodeForFunctionsAndBindings
+ // for why this function is necessary
+ void handleTopLevelFunctionFormals(QQmlJS::AST::FunctionExpression *node) {
+ if (node && node->formals)
+ node->formals->accept(this);
+ }
+
void enterGlobalEnvironment(ContextType compilationMode);
void enterEnvironment(QQmlJS::AST::Node *node, ContextType compilationMode,
const QString &name);
diff --git a/src/qml/configure.pri b/src/qml/configure.pri
index fcd2eacace..4506a5790d 100644
--- a/src/qml/configure.pri
+++ b/src/qml/configure.pri
@@ -13,7 +13,7 @@ defineTest(qtConfTest_detectPython) {
}
# Make tests.python.location available in configure.json.
- $${1}.location = $$shell_path($$python_path)
+ $${1}.location = $$shell_quote($$shell_path($$python_path))
export($${1}.location)
$${1}.cache += location
export($${1}.cache)
diff --git a/src/qml/debugger/debugger.pri b/src/qml/debugger/debugger.pri
index 1281886816..6f976e149e 100644
--- a/src/qml/debugger/debugger.pri
+++ b/src/qml/debugger/debugger.pri
@@ -15,6 +15,7 @@ qtConfig(qml-debug) {
$$PWD/qqmldebugservice.cpp \
$$PWD/qqmlabstractprofileradapter.cpp \
$$PWD/qqmlprofiler.cpp \
+ $$PWD/qqmldebugserver.cpp \
$$PWD/qqmldebugserviceinterfaces.cpp
}
diff --git a/src/qml/debugger/qqmldebug.cpp b/src/qml/debugger/qqmldebug.cpp
index 58b8ea2c4f..0ca56f3a70 100644
--- a/src/qml/debugger/qqmldebug.cpp
+++ b/src/qml/debugger/qqmldebug.cpp
@@ -44,17 +44,26 @@
#include <private/qqmlengine_p.h>
#include <private/qv4compileddata_p.h>
+#include <atomic>
#include <cstdio>
QT_REQUIRE_CONFIG(qml_debug);
QT_BEGIN_NAMESPACE
+#if __cplusplus >= 202002L
+# define Q_ATOMIC_FLAG_INIT {}
+#else
+# define Q_ATOMIC_FLAG_INIT ATOMIC_FLAG_INIT // deprecated in C++20
+#endif
+
+static std::atomic_flag s_printedWarning = Q_ATOMIC_FLAG_INIT;
+
QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning)
{
- if (!QQmlEnginePrivate::qml_debugging_enabled && printWarning)
+ if (printWarning && !s_printedWarning.test_and_set(std::memory_order_relaxed))
fprintf(stderr, "QML debugging is enabled. Only use this in a safe environment.\n");
- QQmlEnginePrivate::qml_debugging_enabled = true;
+ QQmlEnginePrivate::qml_debugging_enabled.store(true, std::memory_order_relaxed);
}
/*!
diff --git a/src/qml/debugger/qqmldebugconnector.cpp b/src/qml/debugger/qqmldebugconnector.cpp
index 0ef40d6911..01a0723b76 100644
--- a/src/qml/debugger/qqmldebugconnector.cpp
+++ b/src/qml/debugger/qqmldebugconnector.cpp
@@ -111,7 +111,7 @@ QQmlDebugConnector *QQmlDebugConnector::instance()
if (!params)
return nullptr;
- if (!QQmlEnginePrivate::qml_debugging_enabled) {
+ if (!QQmlEnginePrivate::qml_debugging_enabled.load(std::memory_order_relaxed)) {
if (!params->arguments.isEmpty()) {
qWarning().noquote() << QString::fromLatin1(
"QML Debugger: Ignoring \"-qmljsdebugger=%1\". Debugging "
diff --git a/src/qml/debugger/qqmldebugconnector_p.h b/src/qml/debugger/qqmldebugconnector_p.h
index d1ad90adfd..4f7b013160 100644
--- a/src/qml/debugger/qqmldebugconnector_p.h
+++ b/src/qml/debugger/qqmldebugconnector_p.h
@@ -65,6 +65,7 @@ QT_BEGIN_NAMESPACE
class Q_QML_PRIVATE_EXPORT QQmlDebugConnector
{
+ virtual ~QQmlDebugConnector() = default; // don't break 'override' on ~QQmlDebugServer
public:
static QQmlDebugConnector *instance() { return nullptr; }
diff --git a/src/qml/debugger/qqmldebugserver.cpp b/src/qml/debugger/qqmldebugserver.cpp
new file mode 100644
index 0000000000..5119fc4209
--- /dev/null
+++ b/src/qml/debugger/qqmldebugserver.cpp
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml 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 "qqmldebugserver_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQmlDebugServer::~QQmlDebugServer()
+ = default;
+
+QT_END_NAMESPACE
+
+#include "moc_qqmldebugserver_p.cpp"
diff --git a/src/qml/debugger/qqmldebugserver_p.h b/src/qml/debugger/qqmldebugserver_p.h
index e848b00bda..c99155051c 100644
--- a/src/qml/debugger/qqmldebugserver_p.h
+++ b/src/qml/debugger/qqmldebugserver_p.h
@@ -62,6 +62,7 @@ class Q_QML_PRIVATE_EXPORT QQmlDebugServer : public QQmlDebugConnector
{
Q_OBJECT
public:
+ ~QQmlDebugServer() override;
virtual void setDevice(QIODevice *socket) = 0;
};
diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h
index d3eedab1c6..ed1e011830 100644
--- a/src/qml/debugger/qqmlprofiler_p.h
+++ b/src/qml/debugger/qqmlprofiler_p.h
@@ -176,7 +176,7 @@ public:
RefLocation(QV4::ExecutableCompilationUnit *ref, const QUrl &url,
const QV4::CompiledData::Object *obj, const QString &type)
- : Location(QQmlSourceLocation(type, obj->location.line, obj->location.column), url),
+ : Location(QQmlSourceLocation(type, obj->location.line(), obj->location.column()), url),
locationType(Creating), sent(false)
{
unit = ref;
diff --git a/src/qml/doc/src/javascript/finetuning.qdoc b/src/qml/doc/src/javascript/finetuning.qdoc
index fcd710db8b..35310ee051 100644
--- a/src/qml/doc/src/javascript/finetuning.qdoc
+++ b/src/qml/doc/src/javascript/finetuning.qdoc
@@ -82,9 +82,12 @@ Running JavaScript code can be influenced by a few environment variables, partic
\li \c{QV4_MAX_CALL_DEPTH}
\li Stack overflows when running (as opposed to compiling) JavaScript are prevented by
controlling the call depth: the number of nested function invocations. By
- default, an exception is generated if the call depth exceeds 1234. If it contains a
- number, this environment variable overrides the maximum call depth. Beware that the
- recursion limit when compiling JavaScript is not affected.
+ default, an exception is generated if the call depth exceeds a maximum number tuned
+ to the platform's default stack size. If the \c{QV4_MAX_CALL_DEPTH} environment
+ variable contains a number, this number is used as maximum call depth. Beware that
+ the recursion limit when compiling JavaScript is not affected. The default maximum
+ call depth is 1234 on most platforms. On QNX it is 640 because on QNX the default
+ stack size is smaller than on most platforms.
\row
\li \c{QV4_MM_AGGRESSIVE_GC}
\li Setting this environment variable runs the garbage collector before each memory
diff --git a/src/qml/inlinecomponentutils_p.h b/src/qml/inlinecomponentutils_p.h
index 99b28349cd..c3ab0e1fe5 100644
--- a/src/qml/inlinecomponentutils_p.h
+++ b/src/qml/inlinecomponentutils_p.h
@@ -55,24 +55,38 @@
namespace icutils {
struct Node {
+private:
+ using IndexType = std::vector<QV4::CompiledData::InlineComponent>::size_type;
+ using IndexField = quint32_le_bitfield_member<0, 30, IndexType>;
+ using TemporaryMarkField = quint32_le_bitfield_member<30, 1>;
+ using PermanentMarkField = quint32_le_bitfield_member<31, 1>;
+ quint32_le_bitfield_union<IndexField, TemporaryMarkField, PermanentMarkField> m_data;
+
+public:
Node() = default;
Node(const Node &) = default;
Node(Node &&) = default;
Node& operator=(Node const &) = default;
Node& operator=(Node &&) = default;
- bool operator==(Node const &other) const {return index == other.index;}
+ bool operator==(Node const &other) const {return m_data.data() == other.m_data.data(); }
+
+ Node(IndexType s) : m_data(QSpecialIntegerBitfieldZero) { m_data.set<IndexField>(s); }
+
+ bool hasPermanentMark() const { return m_data.get<PermanentMarkField>(); }
+ bool hasTemporaryMark() const { return m_data.get<TemporaryMarkField>(); }
+
+ void setPermanentMark()
+ {
+ m_data.set<TemporaryMarkField>(0);
+ m_data.set<PermanentMarkField>(1);
+ }
- Node(std::vector<QV4::CompiledData::InlineComponent>::size_type s) {
- index = quint32(s);
- temporaryMark = 0;
- permanentMark = 0;
+ void setTemporaryMark()
+ {
+ m_data.set<TemporaryMarkField>(1);
}
- union {
- quint32_le_bitfield<0, 30> index;
- quint32_le_bitfield<30, 1> temporaryMark;
- quint32_le_bitfield<31, 1> permanentMark;
- };
+ IndexType index() const { return m_data.get<IndexField>(); }
};
using AdjacencyList = std::vector<std::vector<Node*>>;
@@ -107,8 +121,11 @@ void fillAdjacencyListForInlineComponents(ObjectContainer *objectContainer, Adja
auto referencedInICObjectIndex = ic.objectIndex + 1;
while (int(referencedInICObjectIndex) < objectContainer->objectCount()) {
auto potentiallyReferencedInICObject = objectContainer->objectAt(referencedInICObjectIndex);
- bool stillInIC = !(potentiallyReferencedInICObject-> flags & QV4::CompiledData::Object::IsInlineComponentRoot)
- && (potentiallyReferencedInICObject-> flags & QV4::CompiledData::Object::InPartOfInlineComponent);
+ bool stillInIC
+ = !potentiallyReferencedInICObject->hasFlag(
+ QV4::CompiledData::Object::IsInlineComponentRoot)
+ && potentiallyReferencedInICObject->hasFlag(
+ QV4::CompiledData::Object::InPartOfInlineComponent);
if (!stillInIC)
break;
createEdgeFromTypeRef(objectContainer->resolvedType(potentiallyReferencedInICObject->inheritedTypeNameIndex));
@@ -118,21 +135,20 @@ void fillAdjacencyListForInlineComponents(ObjectContainer *objectContainer, Adja
};
inline void topoVisit(Node *node, AdjacencyList &adjacencyList, bool &hasCycle, std::vector<Node> &nodesSorted) {
- if (node->permanentMark)
+ if (node->hasPermanentMark())
return;
- if (node->temporaryMark) {
+ if (node->hasTemporaryMark()) {
hasCycle = true;
return;
}
- node->temporaryMark = 1;
+ node->setTemporaryMark();
- auto const &edges = adjacencyList[node->index];
+ auto const &edges = adjacencyList[node->index()];
for (auto edgeTarget =edges.begin(); edgeTarget != edges.end(); ++edgeTarget) {
topoVisit(*edgeTarget, adjacencyList, hasCycle, nodesSorted);
}
- node->temporaryMark = 0;
- node->permanentMark = 1;
+ node->setPermanentMark();
nodesSorted.push_back(*node);
};
@@ -143,7 +159,7 @@ inline std::vector<Node> topoSort(std::vector<Node> &nodes, AdjacencyList &adjac
hasCycle = false;
auto currentNodeIt = std::find_if(nodes.begin(), nodes.end(), [](const Node& node) {
- return node.permanentMark == 0;
+ return !node.hasPermanentMark();
});
// Do a topological sort of all inline components
// afterwards, nodesSorted contains the nodes for the inline components in reverse topological order
@@ -151,7 +167,7 @@ inline std::vector<Node> topoSort(std::vector<Node> &nodes, AdjacencyList &adjac
Node& currentNode = *currentNodeIt;
topoVisit(&currentNode, adjacencyList, hasCycle, nodesSorted);
currentNodeIt = std::find_if(nodes.begin(), nodes.end(), [](const Node& node) {
- return node.permanentMark == 0;
+ return !node.hasPermanentMark();
});
}
return nodesSorted;
diff --git a/src/qml/jit/qv4assemblercommon.cpp b/src/qml/jit/qv4assemblercommon.cpp
index 95070fbb96..b090fc7597 100644
--- a/src/qml/jit/qv4assemblercommon.cpp
+++ b/src/qml/jit/qv4assemblercommon.cpp
@@ -51,6 +51,8 @@
#include <assembler/LinkBuffer.h>
#include <WTFStubs.h>
+#if QT_CONFIG(qml_jit)
+
#undef ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES
QT_BEGIN_NAMESPACE
@@ -370,3 +372,5 @@ void PlatformAssemblerCommon::storeInt32AsValue(int srcInt, Address destAddr)
} // QV4 namepsace
QT_END_NAMESPACE
+
+#endif // QT_CONFIG(qml_jit)
diff --git a/src/qml/jit/qv4assemblercommon_p.h b/src/qml/jit/qv4assemblercommon_p.h
index ead1e757de..c3b1eb34eb 100644
--- a/src/qml/jit/qv4assemblercommon_p.h
+++ b/src/qml/jit/qv4assemblercommon_p.h
@@ -58,7 +58,7 @@
#include <wtf/Vector.h>
#include <assembler/MacroAssembler.h>
-QT_REQUIRE_CONFIG(qml_jit);
+#if QT_CONFIG(qml_jit)
QT_BEGIN_NAMESPACE
@@ -740,4 +740,6 @@ private:
QT_END_NAMESPACE
+#endif // QT_CONFIG(qml_jit)
+
#endif // QV4PLATFORMASSEMBLER_P_H
diff --git a/src/qml/jit/qv4baselineassembler.cpp b/src/qml/jit/qv4baselineassembler.cpp
index dd6a40afe0..7ad131335e 100644
--- a/src/qml/jit/qv4baselineassembler.cpp
+++ b/src/qml/jit/qv4baselineassembler.cpp
@@ -55,6 +55,8 @@
#undef ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES
+#if QT_CONFIG(qml_jit)
+
QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
@@ -1619,3 +1621,5 @@ void BaselineAssembler::ret()
} // QV4 namepsace
QT_END_NAMESPACE
+
+#endif // QT_CONFIG(qml_jit)
diff --git a/src/qml/jit/qv4baselineassembler_p.h b/src/qml/jit/qv4baselineassembler_p.h
index c2c735282b..c6fdab51c5 100644
--- a/src/qml/jit/qv4baselineassembler_p.h
+++ b/src/qml/jit/qv4baselineassembler_p.h
@@ -55,7 +55,7 @@
#include <private/qv4function_p.h>
#include <QHash>
-QT_REQUIRE_CONFIG(qml_jit);
+#if QT_CONFIG(qml_jit)
QT_BEGIN_NAMESPACE
@@ -182,4 +182,6 @@ private:
QT_END_NAMESPACE
+#endif // QT_CONFIG(qml_jit)
+
#endif // QV4BASELINEASSEMBLER_P_H
diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp
index d329a5afec..45150cfffd 100644
--- a/src/qml/jit/qv4baselinejit.cpp
+++ b/src/qml/jit/qv4baselinejit.cpp
@@ -42,6 +42,8 @@
#include <private/qv4lookup_p.h>
#include <private/qv4generatorobject_p.h>
+#if QT_CONFIG(qml_jit)
+
QT_USE_NAMESPACE
using namespace QV4;
using namespace QV4::JIT;
@@ -930,3 +932,6 @@ void BaselineJIT::endInstruction(Instr::Type instr)
{
Q_UNUSED(instr);
}
+
+#endif // QT_CONFIG(qml_jit)
+
diff --git a/src/qml/jit/qv4baselinejit_p.h b/src/qml/jit/qv4baselinejit_p.h
index 284faf0ff0..2b0913169e 100644
--- a/src/qml/jit/qv4baselinejit_p.h
+++ b/src/qml/jit/qv4baselinejit_p.h
@@ -56,7 +56,7 @@
#include <private/qv4instr_moth_p.h>
#include <private/qv4bytecodehandler_p.h>
-QT_REQUIRE_CONFIG(qml_jit);
+#if QT_CONFIG(qml_jit)
QT_BEGIN_NAMESPACE
@@ -220,4 +220,6 @@ private:
QT_END_NAMESPACE
+#endif // QT_CONFIG(qml_jit)
+
#endif // QV4JIT_P_H
diff --git a/src/qml/jsruntime/qv4arrayiterator.cpp b/src/qml/jsruntime/qv4arrayiterator.cpp
index 199b1a728a..51387edf6e 100644
--- a/src/qml/jsruntime/qv4arrayiterator.cpp
+++ b/src/qml/jsruntime/qv4arrayiterator.cpp
@@ -86,18 +86,18 @@ ReturnedValue ArrayIteratorPrototype::method_next(const FunctionObject *b, const
return IteratorPrototype::createIterResultObject(scope.engine, Value::fromInt32(index), false);
}
- ReturnedValue elementValue = a->get(index);
+ QV4::ScopedValue elementValue(scope, a->get(index));
CHECK_EXCEPTION();
if (itemKind == ValueIteratorKind) {
- return IteratorPrototype::createIterResultObject(scope.engine, Value::fromReturnedValue(elementValue), false);
+ return IteratorPrototype::createIterResultObject(scope.engine, elementValue, false);
} else {
Q_ASSERT(itemKind == KeyValueIteratorKind);
ScopedArrayObject resultArray(scope, scope.engine->newArrayObject());
resultArray->arrayReserve(2);
resultArray->arrayPut(0, Value::fromInt32(index));
- resultArray->arrayPut(1, Value::fromReturnedValue(elementValue));
+ resultArray->arrayPut(1, elementValue);
resultArray->setArrayLengthUnchecked(2);
return IteratorPrototype::createIterResultObject(scope.engine, resultArray, false);
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 833df534d6..0a564fc6d5 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -300,6 +300,9 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
if (ok && envMaxGCStackSize > 0)
m_maxGCStackSize = envMaxGCStackSize;
+ // We allocate guard pages around our stacks.
+ const size_t guardPages = 2 * WTF::pageSize();
+
memoryManager = new QV4::MemoryManager(this);
if (maxCallDepth == -1) {
@@ -310,7 +313,11 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok);
if (!ok || maxCallDepth <= 0) {
#if defined(QT_NO_DEBUG) && !defined(__SANITIZE_ADDRESS__) && !__has_feature(address_sanitizer)
+#ifdef Q_OS_QNX
+ maxCallDepth = 640; // QNX's stack is only 512k by default
+#else
maxCallDepth = 1234;
+#endif
#else
// no (tail call) optimization is done, so there'll be a lot mare stack frames active
maxCallDepth = 200;
@@ -323,9 +330,9 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
// reserve space for the JS stack
// we allow it to grow to a bit more than m_maxJSStackSize, as we can overshoot due to ScopedValues
// allocated outside of JIT'ed methods.
- *jsStack = WTF::PageAllocation::allocate(m_maxJSStackSize + 256*1024, WTF::OSAllocator::JSVMStackPages,
- /* writable */ true, /* executable */ false,
- /* includesGuardPages */ true);
+ *jsStack = WTF::PageAllocation::allocate(
+ m_maxJSStackSize + 256*1024 + guardPages, WTF::OSAllocator::JSVMStackPages,
+ /* writable */ true, /* executable */ false, /* includesGuardPages */ true);
jsStackBase = (Value *)jsStack->base();
#ifdef V4_USE_VALGRIND
VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, m_maxJSStackSize + 256*1024);
@@ -333,9 +340,9 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
jsStackTop = jsStackBase;
- *gcStack = WTF::PageAllocation::allocate(m_maxGCStackSize, WTF::OSAllocator::JSVMStackPages,
- /* writable */ true, /* executable */ false,
- /* includesGuardPages */ true);
+ *gcStack = WTF::PageAllocation::allocate(
+ m_maxGCStackSize + guardPages, WTF::OSAllocator::JSVMStackPages,
+ /* writable */ true, /* executable */ false, /* includesGuardPages */ true);
{
ok = false;
@@ -1885,6 +1892,25 @@ int ExecutionEngine::maxGCStackSize() const
return m_maxGCStackSize;
}
+/*!
+ \internal
+ Returns \a length converted to int if its safe to
+ pass to \c Scope::alloc.
+ Otherwise it throws a RangeError, and returns 0.
+ */
+int ExecutionEngine::safeForAllocLength(qint64 len64)
+{
+ if (len64 < 0ll || len64 > qint64(std::numeric_limits<int>::max())) {
+ this->throwRangeError(QStringLiteral("Invalid array length."));
+ return 0;
+ }
+ if (len64 > qint64(this->jsStackLimit - this->jsStackTop)) {
+ this->throwRangeError(QStringLiteral("Array too large for apply()."));
+ return 0;
+ }
+ return len64;
+}
+
ReturnedValue ExecutionEngine::global()
{
return globalObject->asReturnedValue();
@@ -2026,7 +2052,7 @@ void ExecutionEngine::setQmlEngine(QQmlEngine *engine)
static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object)
{
- if (object->as<QV4::QObjectWrapper>() || object->internalClass()->isFrozen)
+ if (object->as<QV4::QObjectWrapper>() || object->internalClass()->isFrozen())
return;
QV4::Scope scope(v4);
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index efe44a324c..dd6e6ed279 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -655,6 +655,7 @@ public:
int maxGCStackSize() const;
bool checkStackLimits();
+ int safeForAllocLength(qint64 len64);
bool canJIT(Function *f = nullptr)
{
@@ -723,6 +724,9 @@ public:
QQmlRefPointer<ExecutableCompilationUnit> loadModule(const QUrl &_url, const ExecutableCompilationUnit *referrer = nullptr);
private:
+ template<int Frames>
+ friend struct ExecutionEngineCallDepthRecorder;
+
#if QT_CONFIG(qml_debug)
QScopedPointer<QV4::Debugging::Debugger> m_debugger;
QScopedPointer<QV4::Profiling::Profiler> m_profiler;
@@ -753,14 +757,17 @@ private:
};
#define CHECK_STACK_LIMITS(v4) if ((v4)->checkStackLimits()) return Encode::undefined(); \
- ExecutionEngineCallDepthRecorder _executionEngineCallDepthRecorder(v4);
+ ExecutionEngineCallDepthRecorder<1> _executionEngineCallDepthRecorder(v4);
+template<int Frames = 1>
struct ExecutionEngineCallDepthRecorder
{
ExecutionEngine *ee;
- ExecutionEngineCallDepthRecorder(ExecutionEngine *e): ee(e) { ++ee->callDepth; }
- ~ExecutionEngineCallDepthRecorder() { --ee->callDepth; }
+ ExecutionEngineCallDepthRecorder(ExecutionEngine *e): ee(e) { ee->callDepth += Frames; }
+ ~ExecutionEngineCallDepthRecorder() { ee->callDepth -= Frames; }
+
+ bool hasOverflow() const { return ee->callDepth >= ExecutionEngine::maxCallDepth; }
};
inline bool ExecutionEngine::checkStackLimits()
diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp
index 2c54388100..09a1e936ad 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit.cpp
+++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp
@@ -155,10 +155,10 @@ QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine)
data->regexpTableSize * sizeof(QV4::Value));
for (uint i = 0; i < data->regexpTableSize; ++i) {
const CompiledData::RegExp *re = data->regexpAt(i);
- uint f = re->flags;
+ uint f = re->flags();
const CompiledData::RegExp::Flags flags = static_cast<CompiledData::RegExp::Flags>(f);
runtimeRegularExpressions[i] = QV4::RegExp::create(
- engine, stringAt(re->stringIndex), flags);
+ engine, stringAt(re->stringIndex()), flags);
}
if (data->lookupTableSize) {
@@ -169,7 +169,7 @@ QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine)
QV4::Lookup *l = runtimeLookups + i;
CompiledData::Lookup::Type type
- = CompiledData::Lookup::Type(uint(compiledLookups[i].type_and_flags));
+ = CompiledData::Lookup::Type(uint(compiledLookups[i].typeAndFlags()));
if (type == CompiledData::Lookup::Type_Getter)
l->getter = QV4::Lookup::getterGeneric;
else if (type == CompiledData::Lookup::Type_Setter)
@@ -178,7 +178,7 @@ QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine)
l->globalGetter = QV4::Lookup::globalGetterGeneric;
else if (type == CompiledData::Lookup::Type_QmlContextPropertyGetter)
l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter;
- l->nameIndex = compiledLookups[i].nameIndex;
+ l->nameIndex = compiledLookups[i].nameIndex();
}
}
@@ -199,8 +199,8 @@ QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine)
runtimeClasses[i]
= runtimeClasses[i]->addMember(
engine->identifierTable->asPropertyKey(
- runtimeStrings[member->nameOffset]),
- member->isAccessor
+ runtimeStrings[member->nameOffset()]),
+ member->isAccessor()
? QV4::Attr_Accessor
: QV4::Attr_Data);
}
@@ -296,24 +296,8 @@ void ExecutableCompilationUnit::unlink()
propertyCaches.clear();
if (runtimeLookups) {
- for (uint i = 0; i < data->lookupTableSize; ++i) {
- QV4::Lookup &l = runtimeLookups[i];
- if (l.getter == QV4::QObjectWrapper::lookupGetter
- || l.getter == QQmlTypeWrapper::lookupSingletonProperty) {
- if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache)
- pc->release();
- } else if (l.getter == QQmlValueTypeWrapper::lookupGetter
- || l.getter == QQmlTypeWrapper::lookupSingletonProperty) {
- if (QQmlPropertyCache *pc = l.qgadgetLookup.propertyCache)
- pc->release();
- }
-
- if (l.qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty
- || l.qmlContextPropertyGetter == QQmlContextWrapper::lookupContextObjectProperty) {
- if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache)
- pc->release();
- }
- }
+ for (uint i = 0; i < data->lookupTableSize; ++i)
+ runtimeLookups[i].releasePropertyCache();
}
dependentScripts.clear();
@@ -384,7 +368,7 @@ IdentifierHash ExecutableCompilationUnit::createNamedObjectsPerComponent(int com
const quint32_le *namedObjectIndexPtr = component->namedObjectsInComponentTable();
for (quint32 i = 0; i < component->nNamedObjectsInComponent; ++i, ++namedObjectIndexPtr) {
const CompiledData::Object *namedObject = objectAt(*namedObjectIndexPtr);
- namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->id);
+ namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->objectId());
}
return *namedObjectsPerComponentCache.insert(componentObjectIndex, namedObjectCache);
}
@@ -437,13 +421,14 @@ void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngi
// We need to first iterate over all inline components, as the containing component might create instances of them
// and in that case we need to add its object count
for (auto nodeIt = nodesSorted.rbegin(); nodeIt != nodesSorted.rend(); ++nodeIt) {
- const auto &ic = allICs.at(nodeIt->index);
+ const auto &ic = allICs.at(nodeIt->index());
int lastICRoot = ic.objectIndex;
for (int i = ic.objectIndex; i<objectCount(); ++i) {
const QV4::CompiledData::Object *obj = objectAt(i);
- bool leftCurrentInlineComponent =
- (i != lastICRoot && obj->flags & QV4::CompiledData::Object::IsInlineComponentRoot)
- || !(obj->flags & QV4::CompiledData::Object::InPartOfInlineComponent);
+ bool leftCurrentInlineComponent
+ = (i != lastICRoot
+ && obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot))
+ || !obj->hasFlag(QV4::CompiledData::Object::InPartOfInlineComponent);
if (leftCurrentInlineComponent)
break;
inlineComponentData[lastICRoot].totalBindingCount += obj->nBindings;
@@ -473,9 +458,9 @@ void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngi
int objectCount = 0;
for (quint32 i = 0, count = this->objectCount(); i < count; ++i) {
const QV4::CompiledData::Object *obj = objectAt(i);
- if (obj->flags & QV4::CompiledData::Object::InPartOfInlineComponent) {
+ if (obj->hasFlag(QV4::CompiledData::Object::InPartOfInlineComponent))
continue;
- }
+
bindingCount += obj->nBindings;
if (auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) {
if (typeRef->type.isValid() && typeRef->type.parserStatusCast() != -1)
@@ -587,7 +572,9 @@ Heap::Module *ExecutableCompilationUnit::instantiate(ExecutionEngine *engine)
if (!valuePtr) {
QString referenceErrorMessage = QStringLiteral("Unable to resolve import reference ");
referenceErrorMessage += importName->toQString();
- engine->throwReferenceError(referenceErrorMessage, fileName(), entry.location.line, entry.location.column);
+ engine->throwReferenceError(
+ referenceErrorMessage, fileName(),
+ entry.location.line(), entry.location.column());
return nullptr;
}
imports[i] = valuePtr;
@@ -603,7 +590,9 @@ Heap::Module *ExecutableCompilationUnit::instantiate(ExecutionEngine *engine)
if (!dependentModuleUnit->resolveExport(importName)) {
QString referenceErrorMessage = QStringLiteral("Unable to resolve re-export reference ");
referenceErrorMessage += importName->toQString();
- engine->throwReferenceError(referenceErrorMessage, fileName(), entry.location.line, entry.location.column);
+ engine->throwReferenceError(
+ referenceErrorMessage, fileName(),
+ entry.location.line(), entry.location.column());
return nullptr;
}
}
@@ -874,7 +863,7 @@ bool ResolvedTypeReferenceMap::addToHash(QCryptographicHash *hash, QQmlEngine *e
QString ExecutableCompilationUnit::bindingValueAsString(const CompiledData::Binding *binding) const
{
using namespace CompiledData;
- switch (binding->type) {
+ switch (binding->type()) {
case Binding::Type_Script:
case Binding::Type_String:
return stringAt(binding->stringIndex);
@@ -922,7 +911,7 @@ QString ExecutableCompilationUnit::bindingValueAsString(const CompiledData::Bind
QString ExecutableCompilationUnit::bindingValueAsScriptString(
const CompiledData::Binding *binding) const
{
- return (binding->type == CompiledData::Binding::Type_String)
+ return (binding->type() == CompiledData::Binding::Type_String)
? CompiledData::Binding::escapedString(stringAt(binding->stringIndex))
: bindingValueAsString(binding);
}
diff --git a/src/qml/jsruntime/qv4executablecompilationunit_p.h b/src/qml/jsruntime/qv4executablecompilationunit_p.h
index 7bfb68da9d..29e82bf2d5 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit_p.h
+++ b/src/qml/jsruntime/qv4executablecompilationunit_p.h
@@ -282,7 +282,7 @@ public:
QString bindingValueAsScriptString(const CompiledData::Binding *binding) const;
double bindingValueAsNumber(const CompiledData::Binding *binding) const
{
- if (binding->type != CompiledData::Binding::Type_Number)
+ if (binding->type() != CompiledData::Binding::Type_Number)
return 0.0;
return constants[binding->value.constantValueIndex].doubleValue();
}
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index aeb4835c40..cf8a53cf9f 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -176,7 +176,8 @@ QString Function::prettyName(const Function *function, const void *code)
QQmlSourceLocation Function::sourceLocation() const
{
- return QQmlSourceLocation(sourceFile(), compiledFunction->location.line, compiledFunction->location.column);
+ return QQmlSourceLocation(
+ sourceFile(), compiledFunction->location.line(), compiledFunction->location.column());
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index cdb3b8942b..8dafe251e0 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -364,15 +364,10 @@ ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, cons
if (!arr)
return v4->throwTypeError();
- const qint64 len64 = arr->getLength();
- if (len64 < 0ll || len64 > qint64(std::numeric_limits<int>::max()))
- return v4->throwRangeError(QStringLiteral("Invalid array length."));
- if (len64 > qint64(v4->jsStackLimit - v4->jsStackTop))
- return v4->throwRangeError(QStringLiteral("Array too large for apply()."));
-
- const uint len = uint(len64);
-
Scope scope(v4);
+ const uint len = v4->safeForAllocLength(arr->getLength());
+ CHECK_EXCEPTION();
+
Value *arguments = scope.alloc<Scope::Uninitialized>(len);
if (len) {
if (ArgumentsObject::isNonStrictArgumentsObject(arr) && !arr->cast<ArgumentsObject>()->fullyCreated()) {
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 1cd2ecffa4..ccc55d869f 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -303,7 +303,6 @@ struct PropertyAttributes
void clear() { m_all = 0; }
bool isEmpty() const { return !m_all; }
- uint flags() const { return m_flags; }
uint all() const { return m_all; }
bool operator==(PropertyAttributes other) {
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index 70849775cb..904c6a5eaf 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -178,7 +178,7 @@ void SharedInternalClassDataPrivate<PropertyKey>::setSize(uint s)
data->values.size = s;
}
-PropertyKey SharedInternalClassDataPrivate<PropertyKey>::at(uint i)
+PropertyKey SharedInternalClassDataPrivate<PropertyKey>::at(uint i) const
{
Q_ASSERT(data && i < size());
return PropertyKey::fromId(data->values.values[i].rawValue());
@@ -265,6 +265,13 @@ namespace Heap {
void InternalClass::init(ExecutionEngine *engine)
{
+// InternalClass is automatically zeroed during allocation:
+// prototype = nullptr;
+// parent = nullptr;
+// size = 0;
+// numRedundantTransitions = 0;
+// flags = 0;
+
Base::init();
new (&propertyTable) PropertyHash();
new (&nameMap) SharedInternalClassData<PropertyKey>(engine);
@@ -273,13 +280,6 @@ void InternalClass::init(ExecutionEngine *engine)
this->engine = engine;
vtable = QV4::InternalClass::staticVTable();
-// prototype = nullptr;
-// parent = nullptr;
-// size = 0;
- extensible = true;
- isFrozen = false;
- isSealed = false;
- isUsedAsProto = false;
protoId = engine->newProtoId();
// Also internal classes need an internal class pointer. Simply make it point to itself
@@ -300,10 +300,8 @@ void InternalClass::init(Heap::InternalClass *other)
prototype = other->prototype;
parent = other;
size = other->size;
- extensible = other->extensible;
- isSealed = other->isSealed;
- isFrozen = other->isFrozen;
- isUsedAsProto = other->isUsedAsProto;
+ numRedundantTransitions = other->numRedundantTransitions;
+ flags = other->flags;
protoId = engine->newProtoId();
internalClass.set(engine, other->internalClass);
@@ -365,7 +363,99 @@ static void addDummyEntry(InternalClass *newClass, PropertyHash::Entry e)
++newClass->size;
}
-Heap::InternalClass *InternalClass::changeMember(PropertyKey identifier, PropertyAttributes data, InternalClassEntry *entry)
+static PropertyAttributes attributesFromFlags(int flags)
+{
+ PropertyAttributes attributes;
+ attributes.m_all = uchar(flags);
+ return attributes;
+}
+
+static Heap::InternalClass *cleanInternalClass(Heap::InternalClass *orig)
+{
+ if (++orig->numRedundantTransitions < Heap::InternalClass::MaxRedundantTransitions)
+ return orig;
+
+ // We will generally add quite a few transitions here. We have 255 redundant ones.
+ // We can expect at least as many significant ones in addition.
+ std::vector<InternalClassTransition> transitions;
+
+ Scope scope(orig->engine);
+ Scoped<QV4::InternalClass> child(scope, orig);
+
+ {
+ quint8 remainingRedundantTransitions = orig->numRedundantTransitions;
+ QSet<PropertyKey> properties;
+ int structureChanges = 0;
+
+ Scoped<QV4::InternalClass> parent(scope, orig->parent);
+ while (parent && remainingRedundantTransitions > 0) {
+ Q_ASSERT(child->d() != scope.engine->classes[ExecutionEngine::Class_Empty]);
+ const auto it = std::find_if(
+ parent->d()->transitions.begin(), parent->d()->transitions.end(),
+ [&child](const InternalClassTransition &t) {
+ return child->d() == t.lookup;
+ });
+ Q_ASSERT(it != parent->d()->transitions.end());
+
+ if (it->flags & InternalClassTransition::StructureChange) {
+ // A structural change. Each kind of structural change has to be recorded only once.
+ if ((structureChanges & it->flags) != it->flags) {
+ transitions.push_back(*it);
+ structureChanges |= it->flags;
+ } else {
+ --remainingRedundantTransitions;
+ }
+ } else if (!properties.contains(it->id)) {
+ // We only need the final state of the property.
+ properties.insert(it->id);
+
+ // Property removal creates _two_ redundant transitions.
+ // We don't have to replay either, but numRedundantTransitions only records one.
+ if (it->flags != 0)
+ transitions.push_back(*it);
+ } else {
+ --remainingRedundantTransitions;
+ }
+
+ child = parent->d();
+ parent = child->d()->parent;
+ Q_ASSERT(child->d() != parent->d());
+ }
+ }
+
+ for (auto it = transitions.rbegin(); it != transitions.rend(); ++it) {
+ switch (it->flags) {
+ case InternalClassTransition::NotExtensible:
+ child = child->d()->nonExtensible();
+ continue;
+ case InternalClassTransition::VTableChange:
+ child = child->d()->changeVTable(it->vtable);
+ continue;
+ case InternalClassTransition::PrototypeChange:
+ child = child->d()->changePrototype(it->prototype);
+ continue;
+ case InternalClassTransition::ProtoClass:
+ child = child->d()->asProtoClass();
+ continue;
+ case InternalClassTransition::Sealed:
+ child = child->d()->sealed();
+ continue;
+ case InternalClassTransition::Frozen:
+ child = child->d()->frozen();
+ continue;
+ default:
+ Q_ASSERT(it->flags != 0);
+ Q_ASSERT(it->flags < InternalClassTransition::StructureChange);
+ child = child->addMember(it->id, attributesFromFlags(it->flags));
+ continue;
+ }
+ }
+
+ return child->d();
+}
+
+Heap::InternalClass *InternalClass::changeMember(
+ PropertyKey identifier, PropertyAttributes data, InternalClassEntry *entry)
{
if (!data.isEmpty())
data.resolve();
@@ -381,7 +471,7 @@ Heap::InternalClass *InternalClass::changeMember(PropertyKey identifier, Propert
}
if (data == propertyData.at(idx))
- return static_cast<Heap::InternalClass *>(this);
+ return this;
Transition temp = { { identifier }, nullptr, int(data.all()) };
Transition &t = lookupOrInsertTransition(temp);
@@ -394,7 +484,8 @@ Heap::InternalClass *InternalClass::changeMember(PropertyKey identifier, Propert
Q_ASSERT(!propertyData.at(idx).isAccessor());
// add a dummy entry for the accessor
- entry->setterIndex = newClass->size;
+ if (entry)
+ entry->setterIndex = newClass->size;
e->setterIndex = newClass->size;
addDummyEntry(newClass, *e);
}
@@ -403,7 +494,8 @@ Heap::InternalClass *InternalClass::changeMember(PropertyKey identifier, Propert
t.lookup = newClass;
Q_ASSERT(t.lookup);
- return newClass;
+
+ return cleanInternalClass(newClass);
}
Heap::InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
@@ -413,7 +505,7 @@ Heap::InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
if (proto)
proto->setUsedAsProto();
Q_ASSERT(prototype != proto);
- Q_ASSERT(!proto || proto->internalClass->isUsedAsProto);
+ Q_ASSERT(!proto || proto->internalClass->isUsedAsProto());
Transition temp = { { PropertyKey::invalid() }, nullptr, Transition::PrototypeChange };
temp.prototype = proto;
@@ -427,8 +519,7 @@ Heap::InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
newClass->prototype = proto;
t.lookup = newClass;
-
- return newClass;
+ return prototype ? cleanInternalClass(newClass) : newClass;
}
Heap::InternalClass *InternalClass::changeVTableImpl(const VTable *vt)
@@ -449,12 +540,14 @@ Heap::InternalClass *InternalClass::changeVTableImpl(const VTable *vt)
t.lookup = newClass;
Q_ASSERT(t.lookup);
Q_ASSERT(newClass->vtable);
- return newClass;
+ return vtable == QV4::InternalClass::staticVTable()
+ ? newClass
+ : cleanInternalClass(newClass);
}
Heap::InternalClass *InternalClass::nonExtensible()
{
- if (!extensible)
+ if (!isExtensible())
return this;
Transition temp = { { PropertyKey::invalid() }, nullptr, Transition::NotExtensible};
@@ -463,7 +556,7 @@ Heap::InternalClass *InternalClass::nonExtensible()
return t.lookup;
Heap::InternalClass *newClass = engine->newClass(this);
- newClass->extensible = false;
+ newClass->flags |= NotExtensible;
t.lookup = newClass;
Q_ASSERT(t.lookup);
@@ -500,7 +593,7 @@ Heap::InternalClass *InternalClass::addMember(PropertyKey identifier, PropertyAt
Heap::InternalClass *InternalClass::addMemberImpl(PropertyKey identifier, PropertyAttributes data, InternalClassEntry *entry)
{
- Transition temp = { { identifier }, nullptr, (int)data.flags() };
+ Transition temp = { { identifier }, nullptr, int(data.all()) };
Transition &t = lookupOrInsertTransition(temp);
if (entry) {
@@ -553,21 +646,23 @@ void InternalClass::removeMember(QV4::Object *object, PropertyKey identifier)
changeMember(object, identifier, Attr_Invalid);
#ifndef QT_NO_DEBUG
- // we didn't remove the data slot, just made it inaccessible
- Q_ASSERT(object->internalClass()->size == oldClass->size);
+ // We didn't remove the data slot, just made it inaccessible.
+ // ... unless we've rebuilt the whole class. Then all the deleted properties are gone.
+ Q_ASSERT(object->internalClass()->numRedundantTransitions == 0
+ || object->internalClass()->size == oldClass->size);
#endif
}
Heap::InternalClass *InternalClass::sealed()
{
- if (isSealed)
+ if (isSealed())
return this;
Transition temp = { { PropertyKey::invalid() }, nullptr, InternalClassTransition::Sealed };
Transition &t = lookupOrInsertTransition(temp);
if (t.lookup) {
- Q_ASSERT(t.lookup && t.lookup->isSealed);
+ Q_ASSERT(t.lookup && t.lookup->isSealed());
return t.lookup;
}
@@ -575,7 +670,7 @@ Heap::InternalClass *InternalClass::sealed()
Scoped<QV4::InternalClass> ic(scope, engine->newClass(this));
Heap::InternalClass *s = ic->d();
- if (!isFrozen) { // freezing also makes all properties non-configurable
+ if (!isFrozen()) { // freezing also makes all properties non-configurable
for (uint i = 0; i < size; ++i) {
PropertyAttributes attrs = propertyData.at(i);
if (attrs.isEmpty())
@@ -584,7 +679,7 @@ Heap::InternalClass *InternalClass::sealed()
s->propertyData.set(i, attrs);
}
}
- s->isSealed = true;
+ s->flags |= Sealed;
t.lookup = s;
return s;
@@ -592,14 +687,14 @@ Heap::InternalClass *InternalClass::sealed()
Heap::InternalClass *InternalClass::frozen()
{
- if (isFrozen)
+ if (isFrozen())
return this;
Transition temp = { { PropertyKey::invalid() }, nullptr, InternalClassTransition::Frozen };
Transition &t = lookupOrInsertTransition(temp);
if (t.lookup) {
- Q_ASSERT(t.lookup && t.lookup->isFrozen);
+ Q_ASSERT(t.lookup && t.lookup->isFrozen());
return t.lookup;
}
@@ -616,7 +711,7 @@ Heap::InternalClass *InternalClass::frozen()
attrs.setConfigurable(false);
f->propertyData.set(i, attrs);
}
- f->isFrozen = true;
+ f->flags |= Frozen;
t.lookup = f;
return f;
@@ -640,7 +735,7 @@ InternalClass *InternalClass::cryopreserved()
bool InternalClass::isImplicitlyFrozen() const
{
- if (isFrozen)
+ if (isFrozen())
return true;
for (uint i = 0; i < size; ++i) {
@@ -656,7 +751,7 @@ bool InternalClass::isImplicitlyFrozen() const
Heap::InternalClass *InternalClass::asProtoClass()
{
- if (isUsedAsProto)
+ if (isUsedAsProto())
return this;
Transition temp = { { PropertyKey::invalid() }, nullptr, Transition::ProtoClass };
@@ -665,7 +760,7 @@ Heap::InternalClass *InternalClass::asProtoClass()
return t.lookup;
Heap::InternalClass *newClass = engine->newClass(this);
- newClass->isUsedAsProto = true;
+ newClass->flags |= UsedAsProto;
t.lookup = newClass;
Q_ASSERT(t.lookup);
@@ -685,7 +780,7 @@ static void updateProtoUsage(Heap::Object *o, Heap::InternalClass *ic)
void InternalClass::updateProtoUsage(Heap::Object *o)
{
- Q_ASSERT(isUsedAsProto);
+ Q_ASSERT(isUsedAsProto());
Heap::InternalClass *ic = engine->internalClasses(EngineBase::Class_Empty);
Q_ASSERT(!ic->prototype);
@@ -698,6 +793,9 @@ void InternalClass::markObjects(Heap::Base *b, MarkStack *stack)
if (ic->prototype)
ic->prototype->mark(stack);
+ if (ic->parent)
+ ic->parent->mark(stack);
+
ic->nameMap.mark(stack);
}
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index 403702ae55..a5a1471cf1 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -172,7 +172,7 @@ struct SharedInternalClassDataPrivate<PropertyAttributes> {
uint size() const { return m_size; }
void setSize(uint s) { m_size = s; }
- PropertyAttributes at(uint i) { Q_ASSERT(data && i < m_alloc); return data[i]; }
+ PropertyAttributes at(uint i) const { Q_ASSERT(data && i < m_alloc); return data[i]; }
void set(uint i, PropertyAttributes t) { Q_ASSERT(data && i < m_alloc); data[i] = t; }
void mark(MarkStack *) {}
@@ -197,7 +197,7 @@ struct SharedInternalClassDataPrivate<PropertyKey> {
uint size() const;
void setSize(uint s);
- PropertyKey at(uint i);
+ PropertyKey at(uint i) const;
void set(uint i, PropertyKey t);
void mark(MarkStack *s);
@@ -290,24 +290,33 @@ struct InternalClassTransition
int flags;
enum {
// range 0-0xff is reserved for attribute changes
- NotExtensible = 0x100,
- VTableChange = 0x200,
- PrototypeChange = 0x201,
- ProtoClass = 0x202,
- Sealed = 0x203,
- Frozen = 0x204
+ StructureChange = 0x100,
+ NotExtensible = StructureChange | (1 << 0),
+ VTableChange = StructureChange | (1 << 1),
+ PrototypeChange = StructureChange | (1 << 2),
+ ProtoClass = StructureChange | (1 << 3),
+ Sealed = StructureChange | (1 << 4),
+ Frozen = StructureChange | (1 << 5),
};
bool operator==(const InternalClassTransition &other) const
{ return id == other.id && flags == other.flags; }
bool operator<(const InternalClassTransition &other) const
- { return id < other.id || (id == other.id && flags < other.flags); }
+ { return flags < other.flags || (flags == other.flags && id < other.id); }
};
namespace Heap {
struct InternalClass : Base {
+ enum Flag {
+ NotExtensible = 1 << 0,
+ Sealed = 1 << 1,
+ Frozen = 1 << 2,
+ UsedAsProto = 1 << 3,
+ };
+ enum { MaxRedundantTransitions = 255 };
+
ExecutionEngine *engine;
const VTable *vtable;
quintptr protoId; // unique across the engine, gets changed whenever the proto chain changes
@@ -323,10 +332,13 @@ struct InternalClass : Base {
InternalClassTransition &lookupOrInsertTransition(const InternalClassTransition &t);
uint size;
- bool extensible;
- bool isSealed;
- bool isFrozen;
- bool isUsedAsProto;
+ quint8 numRedundantTransitions;
+ quint8 flags;
+
+ bool isExtensible() const { return !(flags & NotExtensible); }
+ bool isSealed() const { return flags & Sealed; }
+ bool isFrozen() const { return flags & Frozen; }
+ bool isUsedAsProto() const { return flags & UsedAsProto; }
void init(ExecutionEngine *engine);
void init(InternalClass *other);
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index d3ea50867a..db6fb39695 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -41,6 +41,7 @@
#include "qv4jscall_p.h"
#include "qv4string_p.h"
#include <private/qv4identifiertable_p.h>
+#include <private/qv4qobjectwrapper_p.h>
QT_BEGIN_NAMESPACE
@@ -144,47 +145,76 @@ ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Va
return l->resolvePrimitiveGetter(engine, object);
}
+static inline void setupObjectLookupTwoClasses(Lookup *l, const Lookup &first, const Lookup &second)
+{
+ Heap::InternalClass *ic1 = first.objectLookup.ic;
+ const uint offset1 = first.objectLookup.offset;
+ Heap::InternalClass *ic2 = second.objectLookup.ic;
+ const uint offset2 = second.objectLookup.offset;
+
+ l->objectLookupTwoClasses.ic = ic1;
+ l->objectLookupTwoClasses.ic2 = ic2;
+ l->objectLookupTwoClasses.offset = offset1;
+ l->objectLookupTwoClasses.offset2 = offset2;
+}
+
+static inline void setupProtoLookupTwoClasses(Lookup *l, const Lookup &first, const Lookup &second)
+{
+ const quintptr protoId1 = first.protoLookup.protoId;
+ const Value *data1 = first.protoLookup.data;
+ const quintptr protoId2 = second.protoLookup.protoId;
+ const Value *data2 = second.protoLookup.data;
+
+ l->protoLookupTwoClasses.protoId = protoId1;
+ l->protoLookupTwoClasses.protoId2 = protoId2;
+ l->protoLookupTwoClasses.data = data1;
+ l->protoLookupTwoClasses.data2 = data2;
+}
+
ReturnedValue Lookup::getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object)
{
if (const Object *o = object.as<Object>()) {
- Lookup first = *l;
- Lookup second = *l;
- ReturnedValue result = second.resolveGetter(engine, o);
-
- if (first.getter == getter0Inline && (second.getter == getter0Inline || second.getter == getter0MemberData)) {
- l->objectLookupTwoClasses.ic = first.objectLookup.ic;
- l->objectLookupTwoClasses.ic2 = second.objectLookup.ic;
- l->objectLookupTwoClasses.offset = first.objectLookup.offset;
- l->objectLookupTwoClasses.offset2 = second.objectLookup.offset;
- l->getter = second.getter == getter0Inline ? getter0Inlinegetter0Inline : getter0Inlinegetter0MemberData;
+ // Do the resolution on a second lookup, then merge.
+ Lookup second;
+ memset(&second, 0, sizeof(Lookup));
+ second.nameIndex = l->nameIndex;
+ second.getter = getterGeneric;
+ const ReturnedValue result = second.resolveGetter(engine, o);
+
+ if (l->getter == getter0Inline
+ && (second.getter == getter0Inline || second.getter == getter0MemberData)) {
+ setupObjectLookupTwoClasses(l, *l, second);
+ l->getter = (second.getter == getter0Inline)
+ ? getter0Inlinegetter0Inline
+ : getter0Inlinegetter0MemberData;
return result;
}
- if (first.getter == getter0MemberData && (second.getter == getter0Inline || second.getter == getter0MemberData)) {
- l->objectLookupTwoClasses.ic = second.objectLookup.ic;
- l->objectLookupTwoClasses.ic2 = first.objectLookup.ic;
- l->objectLookupTwoClasses.offset = second.objectLookup.offset;
- l->objectLookupTwoClasses.offset2 = first.objectLookup.offset;
- l->getter = second.getter == getter0Inline ? getter0Inlinegetter0MemberData : getter0MemberDatagetter0MemberData;
+
+ if (l->getter == getter0MemberData
+ && (second.getter == getter0Inline || second.getter == getter0MemberData)) {
+ setupObjectLookupTwoClasses(l, second, *l);
+ l->getter = (second.getter == getter0Inline)
+ ? getter0Inlinegetter0MemberData
+ : getter0MemberDatagetter0MemberData;
return result;
}
- if (first.getter == getterProto && second.getter == getterProto) {
- l->protoLookupTwoClasses.protoId = first.protoLookup.protoId;
- l->protoLookupTwoClasses.protoId2 = second.protoLookup.protoId;
- l->protoLookupTwoClasses.data = first.protoLookup.data;
- l->protoLookupTwoClasses.data2 = second.protoLookup.data;
+
+
+ if (l->getter == getterProto && second.getter == getterProto) {
+ setupProtoLookupTwoClasses(l, *l, second);
l->getter = getterProtoTwoClasses;
return result;
}
- if (first.getter == getterProtoAccessor && second.getter == getterProtoAccessor) {
- l->protoLookupTwoClasses.protoId = first.protoLookup.protoId;
- l->protoLookupTwoClasses.protoId2 = second.protoLookup.protoId;
- l->protoLookupTwoClasses.data = first.protoLookup.data;
- l->protoLookupTwoClasses.data2 = second.protoLookup.data;
+
+ if (l->getter == getterProtoAccessor && second.getter == getterProtoAccessor) {
+ setupProtoLookupTwoClasses(l, *l, second);
l->getter = getterProtoAccessorTwoClasses;
return result;
}
+ // If any of the above options were true, the propertyCache was inactive.
+ second.releasePropertyCache();
}
l->getter = getterFallback;
@@ -371,7 +401,19 @@ ReturnedValue Lookup::getterIndexed(Lookup *l, ExecutionEngine *engine, const Va
}
l->getter = getterFallback;
return getterFallback(l, engine, object);
+}
+ReturnedValue Lookup::getterQObject(Lookup *lookup, ExecutionEngine *engine, const Value &object)
+{
+ const auto revertLookup = [lookup, engine, &object]() {
+ lookup->qobjectLookup.propertyCache->release();
+ lookup->qobjectLookup.propertyCache = nullptr;
+ lookup->getter = Lookup::getterGeneric;
+ return Lookup::getterGeneric(lookup, engine, object);
+ };
+
+ return QObjectWrapper::lookupGetterImpl(
+ lookup, engine, object, /*useOriginalProperty*/ false, revertLookup);
}
ReturnedValue Lookup::primitiveGetterProto(Lookup *l, ExecutionEngine *engine, const Value &object)
@@ -463,23 +505,30 @@ bool Lookup::setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, co
bool Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
- Lookup first = *l;
- Lookup second = *l;
+ // A precondition of this method is that l->objectLookup is the active variant of the union.
+ Q_ASSERT(l->setter == setter0MemberData || l->setter == setter0Inline);
if (object.isObject()) {
+
+ // As l->objectLookup is active, we can stash some members here, before resolving.
+ Heap::InternalClass *ic = l->objectLookup.ic;
+ const uint index = l->objectLookup.index;
+
if (!l->resolveSetter(engine, static_cast<Object *>(&object), value)) {
l->setter = setterFallback;
return false;
}
if (l->setter == Lookup::setter0MemberData || l->setter == Lookup::setter0Inline) {
- l->objectLookupTwoClasses.ic = first.objectLookup.ic;
- l->objectLookupTwoClasses.ic2 = second.objectLookup.ic;
- l->objectLookupTwoClasses.offset = first.objectLookup.index;
- l->objectLookupTwoClasses.offset2 = second.objectLookup.index;
+ l->objectLookupTwoClasses.ic = ic;
+ l->objectLookupTwoClasses.ic2 = ic;
+ l->objectLookupTwoClasses.offset = index;
+ l->objectLookupTwoClasses.offset2 = index;
l->setter = setter0setter0;
return true;
}
+
+ l->releasePropertyCache();
}
l->setter = setterFallback;
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 31c90b31f6..6241a81850 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -56,11 +56,17 @@
#include "qv4context_p.h"
#include "qv4object_p.h"
#include "qv4internalclass_p.h"
+#include "qv4qmlcontext_p.h"
+#include <private/qqmltypewrapper_p.h>
+#include <private/qqmlvaluetypewrapper_p.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
+// Note: We cannot hide the copy ctor and assignment operator of this class because it needs to
+// be trivially copyable. But you should never ever copy it. There are refcounted members
+// in there.
struct Q_QML_PRIVATE_EXPORT Lookup {
union {
ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object);
@@ -187,6 +193,7 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
static ReturnedValue getterProtoAccessor(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterProtoAccessorTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterIndexed(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getterQObject(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue primitiveGetterProto(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue primitiveGetterAccessor(Lookup *l, ExecutionEngine *engine, const Value &object);
@@ -216,6 +223,20 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
void clear() {
memset(&markDef, 0, sizeof(markDef));
}
+
+ void releasePropertyCache()
+ {
+ if (getter == getterQObject
+ || getter == QQmlTypeWrapper::lookupSingletonProperty
+ || qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty
+ || qmlContextPropertyGetter == QQmlContextWrapper::lookupContextObjectProperty) {
+ if (QQmlPropertyCache *pc = qobjectLookup.propertyCache)
+ pc->release();
+ } else if (getter == QQmlValueTypeWrapper::lookupGetter) {
+ if (QQmlPropertyCache *pc = qgadgetLookup.propertyCache)
+ pc->release();
+ }
+ }
};
Q_STATIC_ASSERT(std::is_standard_layout<Lookup>::value);
@@ -223,6 +244,33 @@ Q_STATIC_ASSERT(std::is_standard_layout<Lookup>::value);
// across 32-bit and 64-bit (matters when cross-compiling).
Q_STATIC_ASSERT(offsetof(Lookup, getter) == 0);
+inline void setupQObjectLookup(
+ Lookup *lookup, const QQmlData *ddata, QQmlPropertyData *propertyData)
+{
+ lookup->releasePropertyCache();
+ Q_ASSERT(ddata->propertyCache != nullptr);
+ lookup->qobjectLookup.propertyCache = ddata->propertyCache;
+ lookup->qobjectLookup.propertyCache->addref();
+ lookup->qobjectLookup.propertyData = propertyData;
+}
+
+inline void setupQObjectLookup(
+ Lookup *lookup, const QQmlData *ddata, QQmlPropertyData *propertyData,
+ const Object *self)
+{
+ lookup->qobjectLookup.ic = self->internalClass();
+ setupQObjectLookup(lookup, ddata, propertyData);
+}
+
+
+inline void setupQObjectLookup(
+ Lookup *lookup, const QQmlData *ddata, QQmlPropertyData *propertyData,
+ const Object *self, const Object *qmlType)
+{
+ lookup->qobjectLookup.qmlTypeIc = qmlType->internalClass();
+ setupQObjectLookup(lookup, ddata, propertyData, self);
+}
+
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index b723141caa..ac90a7fdb9 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -61,17 +61,52 @@ DEFINE_OBJECT_VTABLE(Object);
void Object::setInternalClass(Heap::InternalClass *ic)
{
- d()->internalClass.set(engine(), ic);
- if (ic->isUsedAsProto)
- ic->updateProtoUsage(d());
Q_ASSERT(ic && ic->vtable);
- uint nInline = d()->vtable()->nInlineProperties;
- if (ic->size <= nInline)
- return;
- bool hasMD = d()->memberData != nullptr;
- uint requiredSize = ic->size - nInline;
- if (!(hasMD && requiredSize) || (hasMD && d()->memberData->values.size < requiredSize))
- d()->memberData.set(ic->engine, MemberData::allocate(ic->engine, requiredSize, d()->memberData));
+ Heap::Object *p = d();
+
+ if (ic->numRedundantTransitions < p->internalClass.get()->numRedundantTransitions) {
+ // IC was rebuilt. The indices are different now. We need to move everything.
+
+ Scope scope(engine());
+
+ // We allocate before setting the new IC. Protect it from GC.
+ Scoped<InternalClass> newIC(scope, ic);
+
+ // Pick the members of the old IC that are still valid in the new IC.
+ // Order them by index in memberData (or inline data).
+ Scoped<MemberData> newMembers(scope, MemberData::allocate(scope.engine, ic->size));
+ for (uint i = 0; i < ic->size; ++i)
+ newMembers->set(scope.engine, i, get(ic->nameMap.at(i)));
+
+ p->internalClass.set(scope.engine, ic);
+ const uint nInline = p->vtable()->nInlineProperties;
+
+ if (ic->size > nInline)
+ p->memberData.set(scope.engine, MemberData::allocate(ic->engine, ic->size - nInline));
+ else
+ p->memberData.set(scope.engine, nullptr);
+
+ const auto &memberValues = newMembers->d()->values;
+ for (uint i = 0; i < ic->size; ++i)
+ setProperty(i, memberValues[i]);
+ } else {
+ // The old indices are still the same. No need to move any values.
+ // We may need to re-allocate, though.
+
+ p->internalClass.set(ic->engine, ic);
+ const uint nInline = p->vtable()->nInlineProperties;
+ if (ic->size > nInline) {
+ const uint requiredSize = ic->size - nInline;
+ if ((p->memberData ? p->memberData->values.size : 0) < requiredSize) {
+ p->memberData.set(ic->engine, MemberData::allocate(
+ ic->engine, requiredSize, p->memberData));
+ }
+ }
+ }
+
+ if (ic->isUsedAsProto())
+ ic->updateProtoUsage(p);
+
}
void Object::getProperty(const InternalClassEntry &entry, Property *p) const
@@ -958,7 +993,7 @@ bool Object::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property
bool Object::virtualIsExtensible(const Managed *m)
{
- return m->d()->internalClass->extensible;
+ return m->d()->internalClass->isExtensible();
}
bool Object::virtualPreventExtensions(Managed *m)
@@ -982,7 +1017,7 @@ bool Object::virtualSetPrototypeOf(Managed *m, const Object *proto)
Heap::Object *protod = proto ? proto->d() : nullptr;
if (current == protod)
return true;
- if (!o->internalClass()->extensible)
+ if (!o->internalClass()->isExtensible())
return false;
Heap::Object *p = protod;
while (p) {
diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp
index 26e1074fe3..1f518966d6 100644
--- a/src/qml/jsruntime/qv4profiling.cpp
+++ b/src/qml/jsruntime/qv4profiling.cpp
@@ -50,8 +50,8 @@ FunctionLocation FunctionCall::resolveLocation() const
{
return FunctionLocation(m_function->name()->toQString(),
m_function->executableCompilationUnit()->fileName(),
- m_function->compiledFunction->location.line,
- m_function->compiledFunction->location.column);
+ m_function->compiledFunction->location.line(),
+ m_function->compiledFunction->location.column());
}
FunctionCallProperties FunctionCall::properties() const
diff --git a/src/qml/jsruntime/qv4promiseobject.cpp b/src/qml/jsruntime/qv4promiseobject.cpp
index ecaff72b22..ac1cc81771 100644
--- a/src/qml/jsruntime/qv4promiseobject.cpp
+++ b/src/qml/jsruntime/qv4promiseobject.cpp
@@ -116,6 +116,8 @@ struct ResolveThenableEvent : public QEvent
} // namespace QV4
QT_END_NAMESPACE
+#include "moc_qv4promiseobject_p.cpp"
+
ReactionHandler::ReactionHandler(QObject *parent)
: QObject(parent)
{}
diff --git a/src/qml/jsruntime/qv4propertykey_p.h b/src/qml/jsruntime/qv4propertykey_p.h
index b2a2ec3dea..81f2331666 100644
--- a/src/qml/jsruntime/qv4propertykey_p.h
+++ b/src/qml/jsruntime/qv4propertykey_p.h
@@ -51,6 +51,7 @@
//
#include <private/qv4global_p.h>
+#include <QtCore/qhashfunctions.h>
QT_BEGIN_NAMESPACE
@@ -145,6 +146,10 @@ public:
bool operator ==(const PropertyKey &other) const { return val == other.val; }
bool operator !=(const PropertyKey &other) const { return val != other.val; }
bool operator <(const PropertyKey &other) const { return val < other.val; }
+ inline friend uint qHash(const PropertyKey &key, uint seed) noexcept
+ {
+ return QT_PREPEND_NAMESPACE(qHash)(key.val, seed);
+ }
};
}
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index 6eece147a6..be6c614eda 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -294,11 +294,7 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
QQmlData *ddata = QQmlData::get(scopeObject, false);
if (ddata && ddata->propertyCache) {
ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, scopeObject)));
- const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue());
- lookup->qobjectLookup.ic = That->internalClass();
- lookup->qobjectLookup.propertyCache = ddata->propertyCache;
- lookup->qobjectLookup.propertyCache->addref();
- lookup->qobjectLookup.propertyData = propertyData;
+ QV4::setupQObjectLookup(lookup, ddata, propertyData, val->objectValue());
lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupScopeObjectProperty;
}
}
@@ -326,11 +322,8 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
QQmlData *ddata = QQmlData::get(context->contextObject, false);
if (ddata && ddata->propertyCache) {
ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, context->contextObject)));
- const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue());
- lookup->qobjectLookup.ic = That->internalClass();
- lookup->qobjectLookup.propertyCache = ddata->propertyCache;
- lookup->qobjectLookup.propertyCache->addref();
- lookup->qobjectLookup.propertyData = propertyData;
+ QV4::setupQObjectLookup(lookup, ddata, propertyData,
+ val->objectValue());
lookup->qmlContextPropertyGetter = contextGetterFunction;
}
} else if (originalLookup) {
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 9899c9274e..94613598af 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -875,26 +875,11 @@ ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, E
return QV4::Object::virtualResolveLookupGetter(object, engine, lookup);
}
- lookup->qobjectLookup.ic = This->internalClass();
- lookup->qobjectLookup.propertyCache = ddata->propertyCache;
- lookup->qobjectLookup.propertyCache->addref();
- lookup->qobjectLookup.propertyData = property;
- lookup->getter = QV4::QObjectWrapper::lookupGetter;
+ QV4::setupQObjectLookup(lookup, ddata, property, This);
+ lookup->getter = QV4::Lookup::getterQObject;
return lookup->getter(lookup, engine, *object);
}
-ReturnedValue QObjectWrapper::lookupGetter(Lookup *lookup, ExecutionEngine *engine, const Value &object)
-{
- const auto revertLookup = [lookup, engine, &object]() {
- lookup->qobjectLookup.propertyCache->release();
- lookup->qobjectLookup.propertyCache = nullptr;
- lookup->getter = Lookup::getterGeneric;
- return Lookup::getterGeneric(lookup, engine, object);
- };
-
- return lookupGetterImpl(lookup, engine, object, /*useOriginalProperty*/ false, revertLookup);
-}
-
bool QObjectWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup,
const Value &value)
{
@@ -1160,8 +1145,7 @@ void Heap::QObjectWrapper::markObjects(Heap::Base *that, QV4::MarkStack *markSta
void QObjectWrapper::destroyObject(bool lastCall)
{
Heap::QObjectWrapper *h = d();
- if (!h->internalClass)
- return; // destroyObject already got called
+ Q_ASSERT(h->internalClass);
if (h->object()) {
QQmlData *ddata = QQmlData::get(h->object(), false);
@@ -1191,7 +1175,7 @@ void QObjectWrapper::destroyObject(bool lastCall)
}
}
- h->~Data();
+ h->destroy();
}
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index ac9cad2bdb..10ba79a5e9 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -183,7 +183,7 @@ struct Q_QML_EXPORT QObjectWrapper : public Object
static ReturnedValue getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property);
static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup);
- static ReturnedValue lookupGetter(Lookup *l, ExecutionEngine *engine, const Value &object);
+
template <typename ReversalFunctor> static ReturnedValue lookupGetterImpl(Lookup *l, ExecutionEngine *engine, const Value &object, bool useOriginalProperty, ReversalFunctor revert);
static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value);
diff --git a/src/qml/jsruntime/qv4reflect.cpp b/src/qml/jsruntime/qv4reflect.cpp
index 2a6c61f044..39a0b03dec 100644
--- a/src/qml/jsruntime/qv4reflect.cpp
+++ b/src/qml/jsruntime/qv4reflect.cpp
@@ -76,7 +76,10 @@ struct CallArgs {
static CallArgs createListFromArrayLike(Scope &scope, const Object *o)
{
- int len = o->getLength();
+ int len = scope.engine->safeForAllocLength(o->getLength());
+ if (scope.engine->hasException)
+ return {nullptr, 0};
+
Value *arguments = scope.alloc(len);
for (int i = 0; i < len; ++i) {
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 5fc94b9ddd..cf2e4ec1dd 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -1530,6 +1530,11 @@ static CallArgs createSpreadArguments(Scope &scope, Value *argv, int argc)
if (done->booleanValue())
break;
++argCount;
+ constexpr auto safetyMargin = 100; // leave some space on the stack for actual work with the elements
+ if (qint64(scope.engine->jsStackLimit - scope.engine->jsStackTop) < safetyMargin) {
+ scope.engine->throwRangeError(QLatin1String("Too many elements in array to use it with the spread operator"));
+ return { nullptr, 0 };
+ }
v = scope.alloc<Scope::Uninitialized>();
}
}
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index 06caf04e5a..da149a67c4 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -981,7 +981,7 @@ void MemoryManager::sweep(bool lastSweep, ClassDestroyStatsCallback classCountPt
if (MultiplyWrappedQObjectMap *multiplyWrappedQObjects = engine->m_multiplyWrappedQObjects) {
for (MultiplyWrappedQObjectMap::Iterator it = multiplyWrappedQObjects->begin(); it != multiplyWrappedQObjects->end();) {
- if (!it.value().isNullOrUndefined())
+ if (it.value().isNullOrUndefined())
it = multiplyWrappedQObjects->erase(it);
else
++it;
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 194f7b4cf7..d7bd93aa0d 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -353,7 +353,9 @@ public:
QQmlSourceLocation sourceLocation() const override final
{
- return QQmlSourceLocation(m_compilationUnit->fileName(), m_binding->valueLocation.line, m_binding->valueLocation.column);
+ return QQmlSourceLocation(
+ m_compilationUnit->fileName(), m_binding->valueLocation.line(),
+ m_binding->valueLocation.column());
}
@@ -532,8 +534,8 @@ QString QQmlBinding::expressionIdentifier() const
{
if (auto f = function()) {
QString url = f->sourceFile();
- uint lineNumber = f->compiledFunction->location.line;
- uint columnNumber = f->compiledFunction->location.column;
+ uint lineNumber = f->compiledFunction->location.line();
+ uint columnNumber = f->compiledFunction->location.column();
return url + QString::asprintf(":%u:%u", lineNumber, columnNumber);
}
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index c785f8ef51..6e0956472f 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -1436,8 +1436,10 @@ QQmlError QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(const RequiredP
}
error.setDescription(description);
error.setUrl(unsetRequiredProperty.fileUrl);
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(unsetRequiredProperty.location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(unsetRequiredProperty.location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(
+ unsetRequiredProperty.location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(
+ unsetRequiredProperty.location.column()));
return error;
}
@@ -1775,3 +1777,4 @@ void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s)
QT_END_NAMESPACE
#include "moc_qqmlcomponent.cpp"
+#include "moc_qqmlcomponentattached_p.cpp"
diff --git a/src/qml/qml/qqmlcomponentattached_p.h b/src/qml/qml/qqmlcomponentattached_p.h
index 8ecd9da17d..d7c04a82f1 100644
--- a/src/qml/qml/qqmlcomponentattached_p.h
+++ b/src/qml/qml/qqmlcomponentattached_p.h
@@ -58,6 +58,7 @@
QT_BEGIN_NAMESPACE
+// implemented in qqmlcomponent.cpp
class Q_QML_PRIVATE_EXPORT QQmlComponentAttached : public QObject
{
Q_OBJECT
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index 5e6e1187e2..172557b7c2 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -102,8 +102,8 @@ void QQmlCustomParser::clearErrors()
void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const QString &description)
{
QQmlError error;
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
error.setDescription(description);
exceptions << error;
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index dcc2f8f7f5..852a673ebd 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -193,7 +193,7 @@ int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject,
\endcode
*/
-bool QQmlEnginePrivate::qml_debugging_enabled = false;
+std::atomic<bool> QQmlEnginePrivate::qml_debugging_enabled{false};
bool QQmlEnginePrivate::s_designerMode = false;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
@@ -1812,7 +1812,7 @@ void QQmlData::deferData(int objectIndex, const QQmlRefPointer<QV4::ExecutableCo
const QV4::CompiledData::Binding *binding = compiledObject->bindingTable();
for (quint32 i = 0; i < compiledObject->nBindings; ++i, ++binding) {
const QQmlPropertyData *property = propertyData.at(i);
- if (property && binding->flags & QV4::CompiledData::Binding::IsDeferredBinding)
+ if (property && binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding))
deferData->bindings.insert(property->coreIndex(), binding);
}
@@ -2671,4 +2671,6 @@ bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
QT_END_NAMESPACE
+#include "moc_qqmlengine_p.cpp"
+
#include "moc_qqmlengine.cpp"
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 263c69e2d8..9160fd8aa2 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -80,6 +80,8 @@
#include <private/qjsengine_p.h>
#include <private/qqmldirparser_p.h>
+#include <atomic>
+
QT_BEGIN_NAMESPACE
class QQmlContext;
@@ -267,7 +269,7 @@ public:
static bool designerMode();
static void activateDesignerMode();
- static bool qml_debugging_enabled;
+ static std::atomic<bool> qml_debugging_enabled;
mutable QMutex networkAccessManagerMutex;
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 10c6c41338..e7263d1850 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -46,7 +46,6 @@
#include <QtCore/qfileinfo.h>
#include <QtCore/qpluginloader.h>
#include <QtCore/qlibraryinfo.h>
-#include <QtCore/qreadwritelock.h>
#include <QtQml/qqmlextensioninterface.h>
#include <QtQml/qqmlextensionplugin.h>
#include <private/qqmlextensionplugin_p.h>
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
index 244f9ad292..3cbd5e17d2 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -279,6 +279,20 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
// get a copy of the engine pointer as it might get reset;
QQmlEnginePrivate *enginePriv = this->enginePriv;
+ // Incubating objects takes quite a bit more stack space than our usual V4 function
+ enum { EstimatedSizeInV4Frames = 2 };
+ QV4::ExecutionEngineCallDepthRecorder<EstimatedSizeInV4Frames> callDepthRecorder(
+ compilationUnit->engine);
+ if (callDepthRecorder.hasOverflow()) {
+ QQmlError error;
+ error.setMessageType(QtCriticalMsg);
+ error.setUrl(compilationUnit->url());
+ error.setDescription(QQmlComponent::tr("Maximum call stack size exceeded."));
+ errors << error;
+ progress = QQmlIncubatorPrivate::Completed;
+ goto finishIncubate;
+ }
+
if (!vmeGuard.isOK()) {
QQmlError error;
error.setMessageType(QtInfoMsg);
diff --git a/src/qml/qml/qqmlirloader.cpp b/src/qml/qml/qqmlirloader.cpp
index 7fa3d211a6..b6b4372faf 100644
--- a/src/qml/qml/qqmlirloader.cpp
+++ b/src/qml/qml/qqmlirloader.cpp
@@ -94,10 +94,11 @@ QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *seriali
object->init(pool, serializedObject->inheritedTypeNameIndex, serializedObject->idNameIndex);
object->indexOfDefaultPropertyOrAlias = serializedObject->indexOfDefaultPropertyOrAlias;
- object->defaultPropertyIsAlias = serializedObject->defaultPropertyIsAlias;
- object->isInlineComponent = serializedObject->flags & QV4::CompiledData::Object::IsInlineComponentRoot;
- object->flags = serializedObject->flags;
- object->id = serializedObject->id;
+ object->defaultPropertyIsAlias = serializedObject->hasAliasAsDefaultProperty();
+ object->isInlineComponent = serializedObject->hasFlag(
+ QV4::CompiledData::Object::IsInlineComponentRoot);
+ object->flags = serializedObject->flags();
+ object->id = serializedObject->objectId();
object->location = serializedObject->location;
object->locationOfIdProperty = serializedObject->locationOfIdProperty;
@@ -108,7 +109,7 @@ QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *seriali
QmlIR::Binding *b = pool->New<QmlIR::Binding>();
*static_cast<QV4::CompiledData::Binding*>(b) = serializedObject->bindingTable()[i];
object->bindings->append(b);
- if (b->type == QV4::CompiledData::Binding::Type_Script) {
+ if (b->type() == QV4::CompiledData::Binding::Type_Script) {
functionIndices.append(b->value.compiledScriptIndex);
b->value.compiledScriptIndex = functionIndices.count() - 1;
diff --git a/src/qml/qml/qqmlloggingcategory.cpp b/src/qml/qml/qqmlloggingcategory.cpp
index b59a26e17e..98dfe62f0c 100644
--- a/src/qml/qml/qqmlloggingcategory.cpp
+++ b/src/qml/qml/qqmlloggingcategory.cpp
@@ -129,7 +129,7 @@ void QQmlLoggingCategory::componentComplete()
{
m_initialized = true;
if (m_name.isNull()) {
- qmlWarning(this) << QLatin1String("Declaring the name of the LoggingCategory is mandatory and cannot be changed later !");
+ qmlWarning(this) << QLatin1String("Declaring the name of a LoggingCategory is mandatory and cannot be changed later");
} else {
QScopedPointer<QLoggingCategory> category(new QLoggingCategory(m_name.constData(), QtMsgType(m_defaultLogLevel)));
m_category.swap(category);
@@ -138,23 +138,30 @@ void QQmlLoggingCategory::componentComplete()
void QQmlLoggingCategory::setDefaultLogLevel(DefaultLogLevel defaultLogLevel)
{
+ if (m_defaultLogLevel == defaultLogLevel)
+ return;
+
if (m_initialized) {
- qmlWarning(this) << QLatin1String("The defaultLogLevel of a LoggingCategory cannot be changed after the Item is created");
+ qmlWarning(this) << QLatin1String("The defaultLogLevel of a LoggingCategory cannot be changed after the component is completed");
return;
}
m_defaultLogLevel = defaultLogLevel;
}
-
void QQmlLoggingCategory::setName(const QString &name)
{
+ const QByteArray newName = name.toUtf8();
+
+ if (m_name == newName)
+ return;
+
if (m_initialized) {
- qmlWarning(this) << QLatin1String("The name of a LoggingCategory cannot be changed after the Item is created");
+ qmlWarning(this) << QLatin1String("The name of a LoggingCategory cannot be changed after the component is completed");
return;
}
- m_name = name.toUtf8();
+ m_name = newName;
}
#include "moc_qqmlloggingcategory_p.cpp"
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 6aeb567a86..33fbab6e6b 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -280,7 +280,7 @@ void QQmlObjectCreator::populateDeferred(QObject *instance, int deferredIndex,
if (binding) {
Q_ASSERT(qmlProperty);
- Q_ASSERT(binding->flags & QV4::CompiledData::Binding::IsDeferredBinding);
+ Q_ASSERT(binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding));
QQmlListProperty<void> savedList;
qSwap(_currentList, savedList);
@@ -342,7 +342,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
int propertyType = property->propType();
if (property->isEnum()) {
- if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum) {
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsResolvedEnum)) {
propertyType = QMetaType::Int;
} else {
// ### This should be resolved earlier at compile time and the binding value should be changed accordingly.
@@ -356,18 +356,18 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
auto assertOrNull = [&](bool ok)
{
- Q_ASSERT(ok || binding->type == QV4::CompiledData::Binding::Type_Null);
+ Q_ASSERT(ok || binding->type() == QV4::CompiledData::Binding::Type_Null);
Q_UNUSED(ok);
};
- auto assertType = [&](QV4::CompiledData::Binding::ValueType type)
+ auto assertType = [&](QV4::CompiledData::Binding::Type type)
{
- Q_ASSERT(binding->type == type || binding->type == QV4::CompiledData::Binding::Type_Null);
+ Q_ASSERT(binding->type()== type || binding->type() == QV4::CompiledData::Binding::Type_Null);
Q_UNUSED(type);
};
if (property->isQObject()) {
- if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Null) {
QObject *value = nullptr;
const bool ok = property->writeProperty(_qobject, &value, propertyWriteFlags);
Q_ASSERT(ok);
@@ -378,7 +378,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
switch (propertyType) {
case QMetaType::QVariant: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Number) {
double n = compilationUnit->bindingValueAsNumber(binding);
if (double(int(n)) == n) {
if (property->isVarProperty()) {
@@ -396,14 +396,14 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
}
- } else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
+ } else if (binding->type() == QV4::CompiledData::Binding::Type_Boolean) {
if (property->isVarProperty()) {
_vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Value::fromBoolean(binding->valueAsBoolean()));
} else {
QVariant value(binding->valueAsBoolean());
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
- } else if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ } else if (binding->type() == QV4::CompiledData::Binding::Type_Null) {
if (property->isVarProperty()) {
_vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Value::nullValue());
} else {
@@ -659,18 +659,24 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
break;
} else if (property->propType() == qMetaTypeId<QJSValue>()) {
QJSValue value;
- if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_Boolean:
value = QJSValue(binding->valueAsBoolean());
- } else if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- double n = compilationUnit->bindingValueAsNumber(binding);
- if (double(int(n)) == n) {
+ break;
+ case QV4::CompiledData::Binding::Type_Number: {
+ const double n = compilationUnit->bindingValueAsNumber(binding);
+ if (double(int(n)) == n)
value = QJSValue(int(n));
- } else
+ else
value = QJSValue(n);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ break;
+ }
+ case QV4::CompiledData::Binding::Type_Null:
value = QJSValue::NullValue;
- } else {
+ break;
+ default:
value = QJSValue(compilationUnit->bindingValueAsString(binding));
+ break;
}
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
@@ -717,8 +723,8 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
if (idProperty && idProperty->isValid() && idProperty->isWritable() && idProperty->propType() == QMetaType::QString) {
QV4::CompiledData::Binding idBinding;
idBinding.propertyNameIndex = 0; // Not used
- idBinding.flags = 0;
- idBinding.type = QV4::CompiledData::Binding::Type_String;
+ idBinding.clearFlags();
+ idBinding.setType(QV4::CompiledData::Binding::Type_String);
idBinding.stringIndex = _compiledObject->idNameIndex;
idBinding.location = _compiledObject->location; // ###
setPropertyValue(idProperty, &idBinding);
@@ -772,10 +778,10 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
}
- if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding)
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsCustomParserBinding))
continue;
- if (binding->flags & QV4::CompiledData::Binding::IsDeferredBinding) {
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding)) {
if (!applyDeferredBindings)
continue;
} else {
@@ -803,7 +809,8 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProperty, const QV4::CompiledData::Binding *binding)
{
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
+ if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
Q_ASSERT(stringAt(compilationUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty());
QV4::ResolvedTypeReference *tr = resolvedType(binding->propertyNameIndex);
Q_ASSERT(tr);
@@ -826,11 +833,13 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
if (bindingProperty && bindingProperty->propType() == qMetaTypeId<QQmlScriptString>()) {
QQmlScriptString ss(compilationUnit->bindingValueAsScriptString(binding),
context->asQQmlContext(), _scopeObject);
- ss.d.data()->bindingId = binding->type == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : (quint32)QQmlBinding::Invalid;
- ss.d.data()->lineNumber = binding->location.line;
- ss.d.data()->columnNumber = binding->location.column;
- ss.d.data()->isStringLiteral = binding->type == QV4::CompiledData::Binding::Type_String;
- ss.d.data()->isNumberLiteral = binding->type == QV4::CompiledData::Binding::Type_Number;
+ ss.d.data()->bindingId = bindingType == QV4::CompiledData::Binding::Type_Script
+ ? binding->value.compiledScriptIndex
+ : (quint32)QQmlBinding::Invalid;
+ ss.d.data()->lineNumber = binding->location.line();
+ ss.d.data()->columnNumber = binding->location.column();
+ ss.d.data()->isStringLiteral = bindingType == QV4::CompiledData::Binding::Type_String;
+ ss.d.data()->isNumberLiteral = bindingType == QV4::CompiledData::Binding::Type_Number;
ss.d.data()->numberValue = compilationUnit->bindingValueAsNumber(binding);
QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor |
@@ -842,7 +851,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
}
QObject *createdSubObject = nullptr;
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
+ if (bindingType == QV4::CompiledData::Binding::Type_Object) {
createdSubObject = createInstance(binding->value.objectIndex, _bindingTarget);
if (!createdSubObject)
return false;
@@ -851,7 +860,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
if (!bindingProperty) // ### error
return true;
- if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
+ const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
+ if (bindingType == QV4::CompiledData::Binding::Type_GroupProperty) {
const QV4::CompiledData::Object *obj = compilationUnit->objectAt(binding->value.objectIndex);
if (stringAt(obj->inheritedTypeNameIndex).isEmpty()) {
@@ -892,13 +902,15 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
}
}
- if (_ddata->hasBindingBit(bindingProperty->coreIndex()) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
+ if (_ddata->hasBindingBit(bindingProperty->coreIndex())
+ && !(bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
+ && !(bindingFlags & QV4::CompiledData::Binding::IsOnAssignment)
&& !_valueTypeProperty)
QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(bindingProperty->coreIndex()));
- if (binding->type == QV4::CompiledData::Binding::Type_Script || binding->isTranslationBinding()) {
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) {
+ if (bindingType == QV4::CompiledData::Binding::Type_Script
+ || binding->isTranslationBinding()) {
+ if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression) {
QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
int signalIndex = _propertyCache->methodIndexToSignalIndex(bindingProperty->coreIndex());
QQmlBoundSignal *bs = new QQmlBoundSignal(_bindingTarget, signalIndex, _scopeObject, engine);
@@ -954,8 +966,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
return true;
}
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) {
+ if (bindingType == QV4::CompiledData::Binding::Type_Object) {
+ if (bindingFlags & QV4::CompiledData::Binding::IsOnAssignment) {
// ### determine value source and interceptor casts ahead of time.
QQmlType type = qmlTypeForObject(createdSubObject);
Q_ASSERT(type.isValid());
@@ -1013,7 +1025,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
}
// Assigning object to signal property?
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
+ if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
if (!bindingProperty->isFunction()) {
recordError(binding->valueLocation, tr("Cannot assign an object to signal property %1").arg(bindingProperty->name(_qobject)));
return false;
@@ -1135,16 +1147,16 @@ void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location,
{
QQmlError error;
error.setUrl(compilationUnit->url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
error.setDescription(description);
errors << error;
}
void QQmlObjectCreator::registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const
{
- if (object->id >= 0)
- context->setIdProperty(object->id, instance);
+ if (object->objectId() >= 0)
+ context->setIdProperty(object->objectId(), instance);
}
void QQmlObjectCreator::createQmlContext()
@@ -1169,7 +1181,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
QQmlParserStatus *parserStatus = nullptr;
bool installPropertyCache = true;
- if (obj->flags & QV4::CompiledData::Object::IsComponent) {
+ if (obj->hasFlag(QV4::CompiledData::Object::IsComponent)) {
isComponent = true;
QQmlComponent *component = new QQmlComponent(engine, compilationUnit.data(), index, parent);
typeName = QStringLiteral("<component>");
@@ -1261,13 +1273,13 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
compilationUnit.data(), obj, typeName, context->url()));
Q_UNUSED(typeName); // only relevant for tracing
- ddata->lineNumber = obj->location.line;
- ddata->columnNumber = obj->location.column;
+ ddata->lineNumber = obj->location.line();
+ ddata->columnNumber = obj->location.column();
ddata->setImplicitDestructible();
// inline components are root objects, but their index is != 0, so we need
// an additional check
- const bool isInlineComponent = obj->flags & QV4::CompiledData::Object::IsInlineComponentRoot;
+ const bool isInlineComponent = obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot);
if (static_cast<quint32>(index) == /*root object*/0 || ddata->rootObjectInCreation || isInlineComponent) {
if (ddata->context) {
Q_ASSERT(ddata->context != context);
@@ -1300,7 +1312,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
if (isContextObject)
context->contextObject = instance;
- if (customParser && obj->flags & QV4::CompiledData::Object::HasCustomParserBindings) {
+ if (customParser && obj->hasFlag(QV4::CompiledData::Object::HasCustomParserBindings)) {
customParser->engine = QQmlEnginePrivate::get(engine);
customParser->imports = compilationUnit->typeNameCache.data();
@@ -1308,9 +1320,8 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
const QV4::CompiledData::Object *obj = compilationUnit->objectAt(index);
const QV4::CompiledData::Binding *binding = obj->bindingTable();
for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
- if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding) {
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsCustomParserBinding))
bindings << binding;
- }
}
customParser->applyBindings(instance, compilationUnit.data(), bindings);
@@ -1506,7 +1517,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
qSwap(_propertyCache, cache);
qSwap(_vmeMetaObject, vmeMetaObject);
- if (_compiledObject->flags & QV4::CompiledData::Object::HasDeferredBindings)
+ if (_compiledObject->hasFlag(QV4::CompiledData::Object::HasDeferredBindings))
_ddata->deferData(_compiledObjectIndex, compilationUnit, context);
QSet<QString> postHocRequired;
@@ -1519,7 +1530,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
QQmlPropertyData *propertyData = _propertyCache->property(_propertyCache->propertyOffset() + propertyIndex);
// only compute stringAt if there's a chance for the lookup to succeed
auto postHocIt = postHocRequired.isEmpty() ? postHocRequired.end() : postHocRequired.find(stringAt(property->nameIndex));
- if (!property->isRequired && postHocRequired.end() == postHocIt)
+ if (!property->isRequired() && postHocRequired.end() == postHocIt)
continue;
if (postHocIt != postHocRequired.end())
postHocRequired.erase(postHocIt);
@@ -1556,12 +1567,12 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
for (int aliasIndex = 0; aliasIndex != _compiledObject->aliasCount(); ++aliasIndex) {
const QV4::CompiledData::Alias* alias = _compiledObject->aliasesBegin() + aliasIndex;
const auto originalAlias = alias;
- while (alias->aliasToLocalAlias)
+ while (alias->isAliasToLocalAlias())
alias = _compiledObject->aliasesBegin() + alias->localAliasIndex;
- Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
+ Q_ASSERT(alias->hasFlag(QV4::CompiledData::Alias::Resolved));
if (!context->idValues->wasSet())
continue;
- QObject *target = context->idValues[alias->targetObjectId].data();
+ QObject *target = context->idValues[alias->targetObjectId()].data();
if (!target)
continue;
QQmlData *targetDData = QQmlData::get(target, /*create*/false);
@@ -1573,7 +1584,11 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
continue;
auto it = sharedState->requiredProperties.find(targetProperty);
if (it != sharedState->requiredProperties.end())
- it->aliasesToRequired.push_back(AliasToRequiredInfo {compilationUnit->stringAt(originalAlias->nameIndex), compilationUnit->finalUrl()});
+ it->aliasesToRequired.push_back(
+ AliasToRequiredInfo {
+ compilationUnit->stringAt(originalAlias->nameIndex()),
+ compilationUnit->finalUrl()
+ });
}
qSwap(_vmeMetaObject, vmeMetaObject);
diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h
index d6a9e73763..db0535c292 100644
--- a/src/qml/qml/qqmlprivate.h
+++ b/src/qml/qml/qqmlprivate.h
@@ -187,6 +187,23 @@ namespace QQmlPrivate
= QQmlPrivate::createSingletonInstance<T>;
};
+ // from https://en.cppreference.com/w/cpp/language/static:
+ // If a const non-inline (since C++17) static data member or a constexpr
+ // static data member (since C++11)(until C++17) is odr-used, a definition
+ // at namespace scope is still required, but it cannot have an initializer.
+ //
+ // If a static data member is declared constexpr, it is implicitly inline
+ // and does not need to be redeclared at namespace scope. This redeclaration
+ // without an initializer (formerly required as shown above) is still
+ // permitted, but is deprecated.
+ //
+ // TL;DR: redundant definitions for static constexpr are required in c++11
+ // but deprecated in c++17.
+ template<typename T>
+ constexpr CreateIntoFunction Constructors<T, true>::createInto;
+ template<typename T>
+ constexpr CreateSingletonFunction Constructors<T, true>::createSingletonInstance;
+
template<typename T>
struct Constructors<T, false>
{
@@ -194,6 +211,12 @@ namespace QQmlPrivate
static constexpr CreateSingletonFunction createSingletonInstance = nullptr;
};
+ // see comment above over the Constructors<T, true> definitions.
+ template<typename T>
+ constexpr CreateIntoFunction Constructors<T, false>::createInto;
+ template<typename T>
+ constexpr CreateSingletonFunction Constructors<T, false>::createSingletonInstance;
+
template<typename T, bool IsVoid = std::is_void<T>::value>
struct ExtendedType;
@@ -205,6 +228,12 @@ namespace QQmlPrivate
static constexpr const QMetaObject *staticMetaObject = nullptr;
};
+ // see comment above over the Constructors<T, true> definitions.
+ template<typename T>
+ constexpr const CreateParentFunction ExtendedType<T, true>::createParent;
+ template<typename T>
+ constexpr const QMetaObject* ExtendedType<T, true>::staticMetaObject;
+
// If it's not void, we actually want an error if the ctor or the metaobject is missing.
template<typename T>
struct ExtendedType<T, false>
@@ -213,6 +242,12 @@ namespace QQmlPrivate
static constexpr const QMetaObject *staticMetaObject = &T::staticMetaObject;
};
+ // see comment above over the Constructors<T, true> definitions.
+ template<typename T>
+ constexpr const CreateParentFunction ExtendedType<T, false>::createParent;
+ template<typename T>
+ constexpr const QMetaObject* ExtendedType<T, false>::staticMetaObject;
+
template<class From, class To, int N>
struct StaticCastSelectorClass
{
@@ -577,6 +612,10 @@ namespace QQmlPrivate
static constexpr bool Value = false;
};
+ // see comment above over the Constructors<T, true> definitions.
+ template<typename T, class C>
+ constexpr bool QmlSingleton<T, C>::Value;
+
template<class T>
struct QmlSingleton<T, QmlVoidT<typename T::QmlIsSingleton>>
{
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index 9eb81e566e..92bd369ccc 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -598,12 +598,8 @@ QObject *QQmlProperty::object() const
*/
QQmlProperty &QQmlProperty::operator=(const QQmlProperty &other)
{
- if (d)
- d->release();
- d = other.d;
- if (d)
- d->addref();
-
+ QQmlProperty copied(other);
+ qSwap(d, copied.d);
return *this;
}
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 6b68a2a288..8a0abf8bdd 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -51,8 +51,8 @@
#include <QtCore/qdebug.h>
#include <QtCore/QCryptographicHash>
+#include <QtCore/private/qtools_p.h>
-#include <ctype.h> // for toupper
#include <limits.h>
#include <algorithm>
@@ -571,7 +571,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
QVarLengthArray<char, 128> str(length+3);
str[0] = 'o';
str[1] = 'n';
- str[2] = toupper(rawName[0]);
+ str[2] = QtMiscUtils::toAsciiUpper(rawName[0]);
if (length > 1)
memcpy(&str[3], &rawName[1], length - 1);
str[length + 2] = '\0';
diff --git a/src/qml/qml/qqmlpropertycachecreator.cpp b/src/qml/qml/qqmlpropertycachecreator.cpp
index 88d80d88ab..de02636d95 100644
--- a/src/qml/qml/qqmlpropertycachecreator.cpp
+++ b/src/qml/qml/qqmlpropertycachecreator.cpp
@@ -110,11 +110,15 @@ QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(int referencing
bool QQmlBindingInstantiationContext::resolveInstantiatingProperty()
{
- if (!instantiatingBinding || instantiatingBinding->type != QV4::CompiledData::Binding::Type_GroupProperty)
+ if (!instantiatingBinding
+ || instantiatingBinding->type() != QV4::CompiledData::Binding::Type_GroupProperty) {
return true;
+ }
+
+ if (!referencingObjectPropertyCache)
+ return false;
Q_ASSERT(referencingObjectIndex >= 0);
- Q_ASSERT(referencingObjectPropertyCache);
Q_ASSERT(instantiatingBinding->propertyNameIndex != 0);
bool notInRevision = false;
@@ -144,6 +148,11 @@ void QQmlPendingGroupPropertyBindings::resolveMissingPropertyCaches(QQmlEnginePr
if (propertyCaches->at(groupPropertyObjectIndex))
continue;
+ if (!pendingBinding.referencingObjectPropertyCache) {
+ pendingBinding.referencingObjectPropertyCache
+ = propertyCaches->at(pendingBinding.referencingObjectIndex);
+ }
+
if (!pendingBinding.resolveInstantiatingProperty())
continue;
diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h
index 3fd6c8b4da..363e4d17fe 100644
--- a/src/qml/qml/qqmlpropertycachecreator_p.h
+++ b/src/qml/qml/qqmlpropertycachecreator_p.h
@@ -67,8 +67,8 @@ inline QQmlError qQmlCompileError(const QV4::CompiledData::Location &location,
const QString &description)
{
QQmlError error;
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
error.setDescription(description);
return error;
}
@@ -196,7 +196,7 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects()
// create meta objects for inline components before compiling actual root component
for (auto nodeIt = nodesSorted.rbegin(); nodeIt != nodesSorted.rend(); ++nodeIt) {
- const auto &ic = allICs[nodeIt->index];
+ const auto &ic = allICs[nodeIt->index()];
QV4::ResolvedTypeReference *typeRef = objectContainer->resolvedType(ic.nameIndex);
Q_ASSERT(propertyCaches->at(ic.objectIndex) == nullptr);
Q_ASSERT(typeRef->typePropertyCache.isNull()); // not set yet
@@ -226,7 +226,7 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecur
const CompiledObject *obj = objectContainer->objectAt(objectIndex);
bool needVMEMetaObject = isVMERequired == VMEMetaObjectIsRequired::Always || obj->propertyCount() != 0 || obj->aliasCount() != 0
|| obj->signalCount() != 0 || obj->functionCount() != 0 || obj->enumCount() != 0
- || (((obj->flags & QV4::CompiledData::Object::IsComponent)
+ || ((obj->hasFlag(QV4::CompiledData::Object::IsComponent)
|| (objectIndex == 0 && isAddressable(objectContainer->url())))
&& !objectContainer->resolvedType(obj->inheritedTypeNameIndex)->isFullyDynamicType);
@@ -234,7 +234,8 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecur
auto binding = obj->bindingsBegin();
auto end = obj->bindingsEnd();
for ( ; binding != end; ++binding) {
- if (binding->type == QV4::CompiledData::Binding::Type_Object && (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Object
+ && (binding->flags() & QV4::CompiledData::Binding::IsOnAssignment)) {
// If the on assignment is inside a group property, we need to distinguish between QObject based
// group properties and value type group properties. For the former the base type is derived from
// the property that references us, for the latter we only need a meta-object on the referencing object
@@ -276,24 +277,24 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecur
}
}
- if (QQmlPropertyCache *thisCache = propertyCaches->at(objectIndex)) {
- auto binding = obj->bindingsBegin();
- auto end = obj->bindingsEnd();
- for ( ; binding != end; ++binding)
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
- QQmlBindingInstantiationContext context(objectIndex, &(*binding), stringAt(binding->propertyNameIndex), thisCache);
-
- // Binding to group property where we failed to look up the type of the
- // property? Possibly a group property that is an alias that's not resolved yet.
- // Let's attempt to resolve it after we're done with the aliases and fill in the
- // propertyCaches entry then.
- if (!context.resolveInstantiatingProperty())
- pendingGroupPropertyBindings->append(context);
-
- QQmlError error = buildMetaObjectRecursively(binding->value.objectIndex, context, VMEMetaObjectIsRequired::Maybe);
- if (error.isValid())
- return error;
- }
+ QQmlPropertyCache *thisCache = propertyCaches->at(objectIndex);
+ auto binding = obj->bindingsBegin();
+ auto end = obj->bindingsEnd();
+ for ( ; binding != end; ++binding) {
+ if (binding->type() >= QV4::CompiledData::Binding::Type_Object) {
+ QQmlBindingInstantiationContext context(objectIndex, &(*binding), stringAt(binding->propertyNameIndex), thisCache);
+
+ // Binding to group property where we failed to look up the type of the
+ // property? Possibly a group property that is an alias that's not resolved yet.
+ // Let's attempt to resolve it after we're done with the aliases and fill in the
+ // propertyCaches entry then.
+ if (!thisCache || !context.resolveInstantiatingProperty())
+ pendingGroupPropertyBindings->append(context);
+
+ QQmlError error = buildMetaObjectRecursively(binding->value.objectIndex, context, VMEMetaObjectIsRequired::Maybe);
+ if (error.isValid())
+ return error;
+ }
}
QQmlError noError;
@@ -390,7 +391,7 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
auto aend = obj->aliasesEnd();
for ( ; a != aend; ++a) {
bool notInRevision = false;
- QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex), &notInRevision);
+ QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex()), &notInRevision);
if (d && d->isFinal())
return qQmlCompileError(a->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property"));
}
@@ -438,7 +439,7 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
for ( ; a != aend; ++a) {
auto flags = QQmlPropertyData::defaultSignalFlags();
- QString changedSigName = stringAt(a->nameIndex) + QLatin1String("Changed");
+ QString changedSigName = stringAt(a->nameIndex()) + QLatin1String("Changed");
seenSignals.insert(changedSigName);
cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
@@ -556,12 +557,13 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
if (type == QV4::CompiledData::BuiltinType::Variant)
propertyFlags.type = QQmlPropertyData::Flags::QVariantType;
} else {
- Q_ASSERT(!p->isBuiltinType);
+ Q_ASSERT(!p->isBuiltinType());
QQmlType qmltype;
bool selfReference = false;
- if (!imports->resolveType(stringAt(p->builtinTypeOrTypeNameIndex), &qmltype, nullptr, nullptr, nullptr,
- nullptr, QQmlType::AnyRegistrationType, &selfReference)) {
+ if (!imports->resolveType(stringAt(p->builtinTypeOrTypeNameIndex()), &qmltype,
+ nullptr, nullptr, nullptr, nullptr,
+ QQmlType::AnyRegistrationType, &selfReference)) {
return qQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type"));
}
@@ -592,13 +594,13 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
typeIds = compilationUnit->typeIdsForComponent();
}
- if (p->isList) {
+ if (p->isList()) {
propertyType = typeIds.listId;
} else {
propertyType = typeIds.id;
}
} else {
- if (p->isList) {
+ if (p->isList()) {
propertyType = qmltype.qListTypeId();
} else {
propertyType = qmltype.typeId();
@@ -606,18 +608,17 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
}
}
- if (p->isList)
+ if (p->isList())
propertyFlags.type = QQmlPropertyData::Flags::QListType;
else
propertyFlags.type = QQmlPropertyData::Flags::QObjectDerivedType;
}
- if (!p->isReadOnly && !p->isList)
+ if (!p->isReadOnly() && !p->isList())
propertyFlags.setIsWritable(true);
-
QString propertyName = stringAt(p->nameIndex);
- if (!obj->defaultPropertyIsAlias && propertyIdx == obj->indexOfDefaultPropertyOrAlias)
+ if (!obj->hasAliasAsDefaultProperty() && propertyIdx == obj->indexOfDefaultPropertyOrAlias)
cache->_defaultPropertyName = propertyName;
cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
propertyType, propertTypeMinorVersion, effectiveSignalIndex);
@@ -633,13 +634,14 @@ template <typename ObjectContainer>
inline int QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter(const QV4::CompiledData::ParameterType &param,
QString *customTypeName)
{
- if (param.indexIsBuiltinType) {
+ if (param.indexIsBuiltinType()) {
// built-in type
- return metaTypeForPropertyType(static_cast<QV4::CompiledData::BuiltinType>(int(param.typeNameIndexOrBuiltinType)));
+ return metaTypeForPropertyType(
+ static_cast<QV4::CompiledData::BuiltinType>(param.typeNameIndexOrBuiltinType()));
}
// lazily resolved type
- const QString typeName = stringAt(param.typeNameIndexOrBuiltinType);
+ const QString typeName = stringAt(param.typeNameIndexOrBuiltinType());
if (customTypeName)
*customTypeName = typeName;
QQmlType qmltype;
@@ -702,7 +704,7 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertie
// from a binding.
for (int i = 1; i < objectContainer->objectCount(); ++i) {
const CompiledObject &component = *objectContainer->objectAt(i);
- if (!(component.flags & QV4::CompiledData::Object::IsComponent))
+ if (!component.hasFlag(QV4::CompiledData::Object::IsComponent))
continue;
const auto rootBinding = component.bindingsBegin();
@@ -725,12 +727,12 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertie
auto alias = object.aliasesBegin();
auto end = object.aliasesEnd();
for ( ; alias != end; ++alias) {
- Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
+ Q_ASSERT(alias->hasFlag(QV4::CompiledData::Alias::Resolved));
- const int targetObjectIndex = objectForId(component, alias->targetObjectId);
+ const int targetObjectIndex = objectForId(component, alias->targetObjectId());
Q_ASSERT(targetObjectIndex >= 0);
- if (alias->aliasToLocalAlias)
+ if (alias->isAliasToLocalAlias())
continue;
if (alias->encodedMetaPropertyIndex == -1)
@@ -772,18 +774,21 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::collectObjectsWithAl
objectsWithAliases->append(objectIndex);
// Stop at Component boundary
- if (object.flags & QV4::CompiledData::Object::IsComponent && objectIndex != /*root object*/0)
+ if (object.hasFlag(QV4::CompiledData::Object::IsComponent) && objectIndex != /*root object*/0)
return;
auto binding = object.bindingsBegin();
auto end = object.bindingsEnd();
for (; binding != end; ++binding) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object
- && binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
- && binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
- continue;
-
- collectObjectsWithAliasesRecursively(binding->value.objectIndex, objectsWithAliases);
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_Object:
+ case QV4::CompiledData::Binding::Type_AttachedProperty:
+ case QV4::CompiledData::Binding::Type_GroupProperty:
+ collectObjectsWithAliasesRecursively(binding->value.objectIndex, objectsWithAliases);
+ break;
+ default:
+ break;
+ }
}
}
@@ -797,12 +802,12 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor
propertyFlags->setIsAlias(true);
- if (alias.aliasToLocalAlias) {
+ if (alias.isAliasToLocalAlias()) {
const QV4::CompiledData::Alias *lastAlias = &alias;
QVarLengthArray<const QV4::CompiledData::Alias *, 4> seenAliases({lastAlias});
do {
- const int targetObjectIndex = objectForId(component, lastAlias->targetObjectId);
+ const int targetObjectIndex = objectForId(component, lastAlias->targetObjectId());
Q_ASSERT(targetObjectIndex >= 0);
const CompiledObject *targetObject = objectContainer->objectAt(targetObjectIndex);
Q_ASSERT(targetObject);
@@ -819,17 +824,17 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor
seenAliases.append(targetAlias);
lastAlias = targetAlias;
- } while (lastAlias->aliasToLocalAlias);
+ } while (lastAlias->isAliasToLocalAlias());
return propertyDataForAlias(component, *lastAlias, type, minorVersion, propertyFlags, enginePriv);
}
- const int targetObjectIndex = objectForId(component, alias.targetObjectId);
+ const int targetObjectIndex = objectForId(component, alias.targetObjectId());
Q_ASSERT(targetObjectIndex >= 0);
const CompiledObject &targetObject = *objectContainer->objectAt(targetObjectIndex);
if (alias.encodedMetaPropertyIndex == -1) {
- Q_ASSERT(alias.flags & QV4::CompiledData::Alias::AliasPointsToPointerObject);
+ Q_ASSERT(alias.hasFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject));
auto *typeRef = objectContainer->resolvedType(targetObject.inheritedTypeNameIndex);
if (!typeRef) {
// Can be caused by the alias target not being a valid id or property. E.g.:
@@ -901,7 +906,8 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor
}
}
- propertyFlags->setIsWritable(!(alias.flags & QV4::CompiledData::Alias::IsReadOnly) && writable);
+ propertyFlags->setIsWritable(!(alias.hasFlag(QV4::CompiledData::Alias::IsReadOnly))
+ && writable);
propertyFlags->setIsResettable(resettable);
return QQmlError();
}
@@ -924,7 +930,7 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesTo
auto alias = object.aliasesBegin();
auto end = object.aliasesEnd();
for ( ; alias != end; ++alias, ++aliasIndex) {
- Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
+ Q_ASSERT(alias->hasFlag(QV4::CompiledData::Alias::Resolved));
int type = 0;
int minorVersion = 0;
@@ -933,9 +939,9 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesTo
if (error.isValid())
return error;
- const QString propertyName = objectContainer->stringAt(alias->nameIndex);
+ const QString propertyName = objectContainer->stringAt(alias->nameIndex());
- if (object.defaultPropertyIsAlias && aliasIndex == object.indexOfDefaultPropertyOrAlias)
+ if (object.hasAliasAsDefaultProperty() && aliasIndex == object.indexOfDefaultPropertyOrAlias)
propertyCache->_defaultPropertyName = propertyName;
propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
@@ -951,7 +957,7 @@ inline int QQmlPropertyCacheAliasCreator<ObjectContainer>::objectForId(const Com
for (quint32 i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) {
const int candidateIndex = component.namedObjectsInComponentTable()[i];
const CompiledObject &candidate = *objectContainer->objectAt(candidateIndex);
- if (candidate.id == id)
+ if (candidate.objectId() == id)
return candidateIndex;
}
return -1;
diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp
index 3a1f33113f..ae8e6e3982 100644
--- a/src/qml/qml/qqmlpropertyvalidator.cpp
+++ b/src/qml/qml/qqmlpropertyvalidator.cpp
@@ -104,10 +104,11 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
validateObject(it->objectIndex, /* instantiatingBinding*/ nullptr);
}
- if (obj->flags & QV4::CompiledData::Object::IsComponent && !(obj->flags & QV4::CompiledData::Object::IsInlineComponentRoot)) {
+ if (obj->hasFlag(QV4::CompiledData::Object::IsComponent)
+ && !obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot)) {
Q_ASSERT(obj->nBindings == 1);
const QV4::CompiledData::Binding *componentBinding = obj->bindingTable();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
+ Q_ASSERT(componentBinding->type() == QV4::CompiledData::Binding::Type_Object);
return validateObject(componentBinding->value.objectIndex, componentBinding);
}
@@ -131,7 +132,7 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
if (!binding->isGroupProperty())
continue;
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment))
continue;
if (populatingValueTypeGroupProperty) {
@@ -160,9 +161,11 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
binding = obj->bindingTable();
for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
QString name = stringAt(binding->propertyNameIndex);
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
+ const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
if (customParser) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
customBindings << binding;
continue;
@@ -175,13 +178,14 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
}
bool bindingToDefaultProperty = false;
- bool isGroupProperty = instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty;
+ bool isGroupProperty = instantiatingBinding
+ && instantiatingBinding->type() == QV4::CompiledData::Binding::Type_GroupProperty;
bool notInRevision = false;
QQmlPropertyData *pd = nullptr;
if (!name.isEmpty()) {
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
+ if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression
+ || bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
pd = propertyResolver.signal(name, &notInRevision);
} else {
pd = propertyResolver.property(name, &notInRevision,
@@ -218,11 +222,11 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
return recordError(binding->location, tr("Invalid attached object assignment"));
}
- if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
+ if (binding->type() >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
const bool populatingValueTypeGroupProperty
= pd
&& QQmlValueTypeFactory::metaObjectForMetaType(pd->propType())
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment);
+ && !binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment);
const QVector<QQmlError> subObjectValidatorErrors
= validateObject(binding->value.objectIndex, binding,
populatingValueTypeGroupProperty);
@@ -231,11 +235,12 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
}
// Signal handlers were resolved and checked earlier in the signal handler conversion pass.
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerExpression)
+ || binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerObject)) {
continue;
+ }
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_AttachedProperty) {
if (instantiatingBinding && (instantiatingBinding->isAttachedProperty() || instantiatingBinding->isGroupProperty())) {
return recordError(binding->location, tr("Attached properties cannot be used here"));
}
@@ -249,15 +254,15 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
if (!pd->isWritable()
&& !pd->isQList()
&& !binding->isGroupProperty()
- && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
+ && !(bindingFlags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
) {
- if (assigningToGroupProperty && binding->type < QV4::CompiledData::Binding::Type_Object)
+ if (assigningToGroupProperty && bindingType < QV4::CompiledData::Binding::Type_Object)
return recordError(binding->valueLocation, tr("Cannot assign a value directly to a grouped property"));
return recordError(binding->valueLocation, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
}
- if (!pd->isQList() && (binding->flags & QV4::CompiledData::Binding::IsListItem)) {
+ if (!pd->isQList() && (bindingFlags & QV4::CompiledData::Binding::IsListItem)) {
QString error;
if (pd->propType() == qMetaTypeId<QQmlScriptString>())
error = tr( "Cannot assign multiple values to a script property");
@@ -268,7 +273,7 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
if (!bindingToDefaultProperty
&& !binding->isGroupProperty()
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
+ && !(bindingFlags & QV4::CompiledData::Binding::IsOnAssignment)
&& assigningToGroupProperty) {
QV4::CompiledData::Location loc = binding->valueLocation;
if (loc < (*assignedGroupProperty)->valueLocation)
@@ -279,11 +284,11 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
return recordError(loc, tr("Cannot assign a value directly to a grouped property"));
}
- if (binding->type < QV4::CompiledData::Binding::Type_Script) {
+ if (bindingType < QV4::CompiledData::Binding::Type_Script) {
QQmlError bindingError = validateLiteralBinding(propertyCache, pd, binding);
if (bindingError.isValid())
return recordError(bindingError);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Object) {
+ } else if (bindingType == QV4::CompiledData::Binding::Type_Object) {
QQmlError bindingError = validateObjectBinding(pd, name, binding);
if (bindingError.isValid())
return recordError(bindingError);
@@ -366,7 +371,7 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
QQmlError noError;
if (property->isEnum()) {
- if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum)
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsResolvedEnum))
return noError;
QString value = compilationUnit->bindingValueAsString(binding);
@@ -384,11 +389,13 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
}
auto warnOrError = [&](const QString &error) {
- if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Null) {
QQmlError warning;
warning.setUrl(compilationUnit->url());
- warning.setLine(qmlConvertSourceCoordinate<quint32, int>(binding->valueLocation.line));
- warning.setColumn(qmlConvertSourceCoordinate<quint32, int>(binding->valueLocation.column));
+ warning.setLine(qmlConvertSourceCoordinate<quint32, int>(
+ binding->valueLocation.line()));
+ warning.setColumn(qmlConvertSourceCoordinate<quint32, int>(
+ binding->valueLocation.column()));
warning.setDescription(error + tr(" - Assigning null to incompatible properties in QML "
"is deprecated. This will become a compile error in "
"future versions of Qt."));
@@ -398,6 +405,7 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
return qQmlCompileError(binding->valueLocation, error);
};
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
switch (property->propType()) {
case QMetaType::QVariant:
break;
@@ -414,19 +422,17 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
}
break;
case QMetaType::QByteArray: {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ if (bindingType != QV4::CompiledData::Binding::Type_String)
return warnOrError(tr("Invalid property assignment: byte array expected"));
- }
}
break;
case QMetaType::QUrl: {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ if (bindingType != QV4::CompiledData::Binding::Type_String)
return warnOrError(tr("Invalid property assignment: url expected"));
- }
}
break;
case QMetaType::UInt: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ if (bindingType == QV4::CompiledData::Binding::Type_Number) {
double d = compilationUnit->bindingValueAsNumber(binding);
if (double(uint(d)) == d)
return noError;
@@ -435,7 +441,7 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
}
break;
case QMetaType::Int: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ if (bindingType == QV4::CompiledData::Binding::Type_Number) {
double d = compilationUnit->bindingValueAsNumber(binding);
if (double(int(d)) == d)
return noError;
@@ -444,13 +450,13 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
}
break;
case QMetaType::Float: {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Number) {
return warnOrError(tr("Invalid property assignment: number expected"));
}
}
break;
case QMetaType::Double: {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Number) {
return warnOrError(tr("Invalid property assignment: number expected"));
}
}
@@ -538,7 +544,7 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
}
break;
case QMetaType::Bool: {
- if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Boolean) {
return warnOrError(tr("Invalid property assignment: boolean expected"));
}
}
@@ -594,12 +600,12 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
default: {
// generate single literal value assignment to a list property if required
if (property->propType() == qMetaTypeId<QList<qreal> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Number) {
return warnOrError(tr("Invalid property assignment: number or array of numbers expected"));
}
break;
} else if (property->propType() == qMetaTypeId<QList<int> >()) {
- bool ok = (binding->type == QV4::CompiledData::Binding::Type_Number);
+ bool ok = (bindingType == QV4::CompiledData::Binding::Type_Number);
if (ok) {
double n = compilationUnit->bindingValueAsNumber(binding);
if (double(int(n)) != n)
@@ -609,12 +615,12 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
return warnOrError(tr("Invalid property assignment: int or array of ints expected"));
break;
} else if (property->propType() == qMetaTypeId<QList<bool> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Boolean) {
return warnOrError(tr("Invalid property assignment: bool or array of bools expected"));
}
break;
} else if (property->propType() == qMetaTypeId<QList<QUrl> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ if (bindingType != QV4::CompiledData::Binding::Type_String) {
return warnOrError(tr("Invalid property assignment: url or array of urls expected"));
}
break;
@@ -628,7 +634,7 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
} else if (property->propType() == qMetaTypeId<QQmlScriptString>()) {
break;
} else if (property->isQObject()
- && binding->type == QV4::CompiledData::Binding::Type_Null) {
+ && bindingType == QV4::CompiledData::Binding::Type_Null) {
break;
}
@@ -690,8 +696,8 @@ QQmlError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *propert
{
QQmlError noError;
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Object);
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment)) {
+ Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Object);
bool isValueSource = false;
bool isPropertyInterceptor = false;
@@ -740,7 +746,8 @@ QQmlError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *propert
}
}
return noError;
- } else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) {
+ } else if (binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerObject)
+ && property->isFunction()) {
return noError;
} else if (isPrimitiveType(propType)) {
auto typeName = QString::fromUtf8(QMetaType::typeName(propType));
diff --git a/src/qml/qml/qqmlscriptblob.cpp b/src/qml/qml/qqmlscriptblob.cpp
index dac21f7ee7..18ea5db4c6 100644
--- a/src/qml/qml/qqmlscriptblob.cpp
+++ b/src/qml/qml/qqmlscriptblob.cpp
@@ -168,8 +168,8 @@ void QQmlScriptBlob::done()
QList<QQmlError> errors = script.script->errors();
QQmlError error;
error.setUrl(url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column()));
error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
errors.prepend(error);
setError(errors);
@@ -237,8 +237,8 @@ void QQmlScriptBlob::initializeFromCompilationUnit(const QQmlRefPointer<QV4::Exe
Q_ASSERT(errors.size());
QQmlError error(errors.takeFirst());
error.setUrl(m_importCache.baseUrl());
- error.setLine(import->location.line);
- error.setColumn(import->location.column);
+ error.setLine(import->location.line());
+ error.setColumn(import->location.column());
errors.prepend(error); // put it back on the list after filling out information.
setError(errors);
return;
diff --git a/src/qml/qml/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp
index f1a6b3bff2..c3c80a2ac5 100644
--- a/src/qml/qml/qqmltypecompiler.cpp
+++ b/src/qml/qml/qqmltypecompiler.cpp
@@ -174,8 +174,8 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
void QQmlTypeCompiler::recordError(const QV4::CompiledData::Location &location, const QString &description)
{
QQmlError error;
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
error.setDescription(description);
error.setUrl(url());
errors << error;
@@ -335,7 +335,8 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
QString propertyName = stringAt(binding->propertyNameIndex);
// Attached property?
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
+ if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
const QmlIR::Object *attachedObj = qmlObjects.at(binding->value.objectIndex);
auto *typeRef = resolvedType(binding->propertyNameIndex);
QQmlType type = typeRef ? typeRef->type : QQmlType();
@@ -438,13 +439,13 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
}
// Binding object to signal means connect the signal to the object's default method.
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerObject;
+ if (bindingType == QV4::CompiledData::Binding::Type_Object) {
+ binding->setFlag(QV4::CompiledData::Binding::IsSignalHandlerObject);
continue;
}
- if (binding->type != QV4::CompiledData::Binding::Type_Script) {
- if (binding->type < QV4::CompiledData::Binding::Type_Script) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Script) {
+ if (bindingType < QV4::CompiledData::Binding::Type_Script) {
COMPILE_EXCEPTION(binding, tr("Cannot assign a value to a signal (expecting a script to be run)"));
} else {
COMPILE_EXCEPTION(binding, tr("Incorrectly specified signal assignment"));
@@ -489,7 +490,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
}
foe->node = functionDeclaration;
binding->propertyNameIndex = compiler->registerString(propertyName);
- binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerExpression;
+ binding->setFlag(QV4::CompiledData::Binding::IsSignalHandlerExpression);
}
return true;
}
@@ -513,11 +514,13 @@ bool QQmlEnumTypeResolver::resolveEnumBindings()
QQmlPropertyResolver resolver(propertyCache);
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
+ const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
+ if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression
+ || bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
continue;
+ }
- if (binding->type != QV4::CompiledData::Binding::Type_Script)
+ if (binding->type() != QV4::CompiledData::Binding::Type_Script)
continue;
const QString propertyName = stringAt(binding->propertyNameIndex);
@@ -548,10 +551,10 @@ bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, const QS
if (enumName.length() > 0 && enumName[0].isLower() && !isQtObject) {
COMPILE_EXCEPTION(binding, tr("Invalid property assignment: Enum value \"%1\" cannot start with a lowercase letter").arg(enumName.toString()));
}
- binding->type = QV4::CompiledData::Binding::Type_Number;
+ binding->setType(QV4::CompiledData::Binding::Type_Number);
binding->value.constantValueIndex = compiler->registerConstant(QV4::Encode((double)enumValue));
// binding->setNumberValueInternal((double)enumValue);
- binding->flags |= QV4::CompiledData::Binding::IsResolvedEnum;
+ binding->setFlag(QV4::CompiledData::Binding::IsResolvedEnum);
return true;
}
@@ -561,10 +564,13 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
if (!prop->isEnum() && !isIntProp)
return true;
- if (!prop->isWritable() && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration))
- COMPILE_EXCEPTION(binding, tr("Invalid property assignment: \"%1\" is a read-only property").arg(stringAt(binding->propertyNameIndex)));
+ if (!prop->isWritable()
+ && !(binding->hasFlag(QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration))) {
+ COMPILE_EXCEPTION(binding, tr("Invalid property assignment: \"%1\" is a read-only property")
+ .arg(stringAt(binding->propertyNameIndex)));
+ }
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script);
+ Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Script);
const QString string = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
if (!string.constData()->isUpper())
return true;
@@ -694,15 +700,21 @@ void QQmlCustomParserScriptIndexer::scanObjectRecursively(int objectIndex, bool
if (!annotateScriptBindings)
annotateScriptBindings = customParsers.contains(obj->inheritedTypeNameIndex);
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_Script:
+ if (annotateScriptBindings) {
+ binding->stringIndex = compiler->registerString(
+ compiler->bindingAsString(obj, binding->value.compiledScriptIndex));
+ }
+ break;
+ case QV4::CompiledData::Binding::Type_Object:
+ case QV4::CompiledData::Binding::Type_AttachedProperty:
+ case QV4::CompiledData::Binding::Type_GroupProperty:
scanObjectRecursively(binding->value.objectIndex, annotateScriptBindings);
- continue;
- } else if (binding->type != QV4::CompiledData::Binding::Type_Script)
- continue;
- if (!annotateScriptBindings)
- continue;
- const QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
- binding->stringIndex = compiler->registerString(script);
+ break;
+ default:
+ break;
+ }
}
}
@@ -731,7 +743,7 @@ void QQmlAliasAnnotator::annotateBindingsToAliases()
bool notInRevision = false;
QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
if (pd && pd->isAlias())
- binding->flags |= QV4::CompiledData::Binding::IsBindingToAlias;
+ binding->setFlag(QV4::CompiledData::Binding::IsBindingToAlias);
}
}
}
@@ -758,7 +770,7 @@ void QQmlScriptStringScanner::scan()
QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Script)
+ if (binding->type() != QV4::CompiledData::Binding::Type_Script)
continue;
bool notInRevision = false;
QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
@@ -804,9 +816,9 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object)
+ if (binding->type() != QV4::CompiledData::Binding::Type_Object)
continue;
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerObject))
continue;
const QmlIR::Object *targetObject = qmlObjects->at(binding->value.objectIndex);
@@ -871,7 +883,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
QmlIR::Binding *syntheticBinding = pool->New<QmlIR::Binding>();
*syntheticBinding = *binding;
- syntheticBinding->type = QV4::CompiledData::Binding::Type_Object;
+ syntheticBinding->setType(QV4::CompiledData::Binding::Type_Object);
QString error = syntheticComponent->appendBinding(syntheticBinding, /*isListBinding*/false);
Q_ASSERT(error.isEmpty());
Q_UNUSED(error);
@@ -932,7 +944,7 @@ bool QQmlComponentAndAliasResolver::resolve()
COMPILE_EXCEPTION(rootBinding, tr("Component elements may not contain properties other than id"));
}
- if (rootBinding->next || rootBinding->type != QV4::CompiledData::Binding::Type_Object)
+ if (rootBinding->next || rootBinding->type() != QV4::CompiledData::Binding::Type_Object)
COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
// For the root object, we are going to collect ids/aliases and resolve them for as a separate
@@ -1000,13 +1012,16 @@ bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
return true;
for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object
- && binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
- && binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
- continue;
-
- if (!collectIdsAndAliases(binding->value.objectIndex))
- return false;
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_Object:
+ case QV4::CompiledData::Binding::Type_AttachedProperty:
+ case QV4::CompiledData::Binding::Type_GroupProperty:
+ if (!collectIdsAndAliases(binding->value.objectIndex))
+ return false;
+ break;
+ default:
+ break;
+ }
}
return true;
@@ -1054,7 +1069,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex)
if (!atLeastOneAliasResolved && !_objectsWithAliases.isEmpty()) {
const QmlIR::Object *obj = qmlObjects->at(_objectsWithAliases.first());
for (auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) {
- if (!(alias->flags & QV4::CompiledData::Alias::Resolved)) {
+ if (!alias->hasFlag(QV4::CompiledData::Alias::Resolved)) {
recordError(alias->location, tr("Circular alias reference detected"));
return false;
}
@@ -1076,7 +1091,7 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
bool seenUnresolvedAlias = false;
for (QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next) {
- if (alias->flags & QV4::CompiledData::Alias::Resolved)
+ if (alias->hasFlag(QV4::CompiledData::Alias::Resolved))
continue;
seenUnresolvedAlias = true;
@@ -1092,8 +1107,8 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex);
Q_ASSERT(targetObject->id >= 0);
- alias->targetObjectId = targetObject->id;
- alias->aliasToLocalAlias = false;
+ alias->setTargetObjectId(targetObject->id);
+ alias->setIsAliasToLocalAlias(false);
const QString aliasPropertyValue = stringAt(alias->propertyNameIndex);
@@ -1110,7 +1125,7 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
QQmlPropertyIndex propIdx;
if (property.isEmpty()) {
- alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
+ alias->setFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject);
} else {
QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex);
if (!targetCache) {
@@ -1129,7 +1144,7 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
bool aliasPointsToOtherAlias = false;
int localAliasIndex = 0;
for (auto targetAlias = targetObject->aliasesBegin(), end = targetObject->aliasesEnd(); targetAlias != end; ++targetAlias, ++localAliasIndex) {
- if (stringAt(targetAlias->nameIndex) == property) {
+ if (stringAt(targetAlias->nameIndex()) == property) {
aliasPointsToOtherAlias = true;
break;
}
@@ -1137,8 +1152,8 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
if (aliasPointsToOtherAlias) {
if (targetObjectIndex == objectIndex) {
alias->localAliasIndex = localAliasIndex;
- alias->aliasToLocalAlias = true;
- alias->flags |= QV4::CompiledData::Alias::Resolved;
+ alias->setIsAliasToLocalAlias(true);
+ alias->setFlag(QV4::CompiledData::Alias::Resolved);
++numResolvedAliases;
continue;
}
@@ -1200,12 +1215,12 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
}
} else {
if (targetProperty->isQObject())
- alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
+ alias->setFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject);
}
}
alias->encodedMetaPropertyIndex = propIdx.toEncoded();
- alias->flags |= QV4::CompiledData::Alias::Resolved;
+ alias->setFlag(QV4::CompiledData::Alias::Resolved);
numResolvedAliases++;
}
@@ -1241,7 +1256,7 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
if (obj->flags & QV4::CompiledData::Object::IsComponent && !obj->isInlineComponent) {
Q_ASSERT(obj->bindingCount() == 1);
const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
+ Q_ASSERT(componentBinding->type() == QV4::CompiledData::Binding::Type_Object);
return scanObject(componentBinding->value.objectIndex);
}
@@ -1279,16 +1294,16 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
QString name = stringAt(binding->propertyNameIndex);
if (customParser) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_AttachedProperty) {
if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
- binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
+ binding->setFlag(QV4::CompiledData::Binding::IsCustomParserBinding);
obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
continue;
}
} else if (QmlIR::IRBuilder::isSignalPropertyName(name)
&& !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
- binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
+ binding->setFlag(QV4::CompiledData::Binding::IsCustomParserBinding);
continue;
}
}
@@ -1307,7 +1322,8 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
bool seenSubObjectWithId = false;
- if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
+ if (binding->type() >= QV4::CompiledData::Binding::Type_Object
+ && (pd || binding->isAttachedProperty())) {
qSwap(_seenObjectWithId, seenSubObjectWithId);
const bool subObjectValid = scanObject(binding->value.objectIndex);
qSwap(_seenObjectWithId, seenSubObjectWithId);
@@ -1316,21 +1332,24 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
_seenObjectWithId |= seenSubObjectWithId;
}
- if (!seenSubObjectWithId && binding->type != QV4::CompiledData::Binding::Type_GroupProperty
+ if (!seenSubObjectWithId
+ && binding->type() != QV4::CompiledData::Binding::Type_GroupProperty
&& !deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) {
- binding->flags |= QV4::CompiledData::Binding::IsDeferredBinding;
+ binding->setFlag(QV4::CompiledData::Binding::IsDeferredBinding);
obj->flags |= QV4::CompiledData::Object::HasDeferredBindings;
}
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
+ const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
+ if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression
+ || bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
continue;
+ }
if (!pd) {
if (customParser) {
obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
- binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
+ binding->setFlag(QV4::CompiledData::Binding::IsCustomParserBinding);
}
}
}
diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp
index 92a90ea677..c7bfcc55b1 100644
--- a/src/qml/qml/qqmltypedata.cpp
+++ b/src/qml/qml/qqmltypedata.cpp
@@ -203,26 +203,20 @@ bool QQmlTypeData::tryLoadFromDiskCache()
Q_ASSERT(errors.size());
QQmlError error(errors.takeFirst());
error.setUrl(m_importCache.baseUrl());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column()));
errors.prepend(error); // put it back on the list after filling out information.
setError(errors);
return false;
}
}
- QQmlType containingType;
- auto containingTypeName = finalUrl().fileName().split(QLatin1Char('.')).first();
- int major = -1, minor = -1;
- QQmlImportNamespace *ns = nullptr;
- m_importCache.resolveType(containingTypeName, &containingType, &major, &minor, &ns);
for (auto&& ic: ics) {
QString const nameString = m_compiledData->stringAt(ic.nameIndex);
- QByteArray const name = nameString.toUtf8();
auto importUrl = finalUrl();
importUrl.setFragment(QString::number(ic.objectIndex));
auto import = new QQmlImportInstance();
- m_importCache.addInlineComponentImport(import, nameString, importUrl, containingType);
+ m_importCache.addInlineComponentImport(import, nameString, importUrl, QQmlType());
}
return true;
@@ -330,8 +324,8 @@ void QQmlTypeData::done()
QList<QQmlError> errors = script.script->errors();
QQmlError error;
error.setUrl(url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column()));
error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
errors.prepend(error);
setError(errors);
@@ -354,8 +348,8 @@ void QQmlTypeData::done()
QList<QQmlError> errors = type.typeData ? type.typeData->errors() : QList<QQmlError>{};
QQmlError error;
error.setUrl(url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column()));
error.setDescription(QQmlTypeLoader::tr("Type %1 has no inline component type called %2").arg(typeName.leftRef(lastDot), type.type.pendingResolutionName()));
errors.prepend(error);
setError(errors);
@@ -370,8 +364,8 @@ void QQmlTypeData::done()
QList<QQmlError> errors = type.typeData->errors();
QQmlError error;
error.setUrl(url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column()));
error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
errors.prepend(error);
setError(errors);
@@ -389,8 +383,8 @@ void QQmlTypeData::done()
QList<QQmlError> errors = type.typeData->errors();
QQmlError error;
error.setUrl(url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column()));
error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
errors.prepend(error);
setError(errors);
@@ -702,8 +696,8 @@ void QQmlTypeData::continueLoadFromIR()
Q_ASSERT(errors.size());
QQmlError error(errors.takeFirst());
error.setUrl(m_importCache.baseUrl());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column()));
errors.prepend(error); // put it back on the list after filling out information.
setError(errors);
return;
@@ -729,8 +723,10 @@ void QQmlTypeData::allDependenciesDone()
QQmlError error;
error.setDescription(QQmlTypeLoader::tr("module \"%1\" is not installed").arg(import->uri));
error.setUrl(m_importCache.baseUrl());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(
+ import->location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(
+ import->location.column()));
errors.prepend(error);
}
}
@@ -864,8 +860,8 @@ void QQmlTypeData::resolveTypes()
bool *selfReferenceDetection = unresolvedRef->needsCreation ? nullptr : &ref.selfReference;
- if (!resolveType(name, majorVersion, minorVersion, ref, unresolvedRef->location.line,
- unresolvedRef->location.column, reportErrors,
+ if (!resolveType(name, majorVersion, minorVersion, ref, unresolvedRef->location.line(),
+ unresolvedRef->location.column(), reportErrors,
QQmlType::AnyRegistrationType, selfReferenceDetection) && reportErrors)
return;
@@ -887,8 +883,7 @@ void QQmlTypeData::resolveTypes()
ref.majorVersion = majorVersion;
ref.minorVersion = minorVersion;
- ref.location.line = unresolvedRef->location.line;
- ref.location.column = unresolvedRef->location.column;
+ ref.location = unresolvedRef->location;
ref.needsCreation = unresolvedRef->needsCreation;
m_resolvedTypes.insert(unresolvedRef.key(), ref);
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 1d66e756fa..01aba47a9a 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -697,8 +697,8 @@ void QQmlTypeLoader::Blob::dependencyComplete(QQmlDataBlob *blob)
Q_ASSERT(errors.size());
QQmlError error(errors.takeFirst());
error.setUrl(m_importCache.baseUrl());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column()));
errors.prepend(error); // put it back on the list after filling out information.
setError(errors);
}
diff --git a/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp b/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp
index af97643163..bcc5306cf8 100644
--- a/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp
+++ b/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp
@@ -72,3 +72,5 @@ void QQmlTypeLoaderNetworkReplyProxy::manualFinished(QNetworkReply *reply)
}
QT_END_NAMESPACE
+
+#include "moc_qqmltypeloadernetworkreplyproxy_p.cpp"
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index fa5d36503d..a6ba4b8cb3 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -419,8 +419,10 @@ ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const
return Encode(false);
QQmlRefPointer<QQmlTypeData> td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl());
- ExecutableCompilationUnit *cu = td->compilationUnit();
- myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId);
+ if (ExecutableCompilationUnit *cu = td->compilationUnit())
+ myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId);
+ else
+ return Encode(false); // It seems myQmlType has some errors, so we could not compile it.
} else {
myQmlType = qenginepriv->metaObjectForType(myTypeId);
}
@@ -458,11 +460,8 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object,
QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext);
if (property) {
ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton)));
- lookup->qobjectLookup.qmlTypeIc = This->internalClass();
- lookup->qobjectLookup.ic = val->objectValue()->internalClass();
- lookup->qobjectLookup.propertyCache = ddata->propertyCache;
- lookup->qobjectLookup.propertyCache->addref();
- lookup->qobjectLookup.propertyData = property;
+ setupQObjectLookup(lookup, ddata, property,
+ val->objectValue(), This);
lookup->getter = QQmlTypeWrapper::lookupSingletonProperty;
return lookup->getter(lookup, engine, *object);
}
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index aa9f4bc1bd..1e0e4e419f 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -231,17 +231,14 @@ void QQmlVMEMetaObjectEndpoint::tryConnect()
const QV4::CompiledData::Alias *aliasData = &metaObject->compiledObject->aliasTable()[aliasId];
if (!aliasData->isObjectAlias()) {
QQmlContextData *ctxt = metaObject->ctxt;
- QObject *target = ctxt->idValues[aliasData->targetObjectId].data();
+ QObject *target = ctxt->idValues[aliasData->targetObjectId()].data();
if (!target)
return;
- QQmlData *targetDData = QQmlData::get(target, /*create*/false);
- if (!targetDData)
- return;
QQmlPropertyIndex encodedIndex = QQmlPropertyIndex::fromEncoded(aliasData->encodedMetaPropertyIndex);
int coreIndex = encodedIndex.coreIndex();
int valueTypeIndex = encodedIndex.valueTypeIndex();
- const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex);
+ const QQmlPropertyData *pd = QQmlData::ensurePropertyCache(qmlEngine(target), target)->property(coreIndex);
if (pd && valueTypeIndex != -1 && !QQmlValueTypeFactory::valueType(pd->propType())) {
// deep alias
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(metaObject->compilationUnit->engine->qmlEngine());
@@ -758,7 +755,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
}
break;
case QV4::CompiledData::BuiltinType::InvalidBuiltin:
- if (property.isList) {
+ if (property.isList()) {
// when reading from the list, we need to find the correct MetaObject,
// namely this. However, obejct->metaObject might point to any MetaObject
// down the inheritance hierarchy, so we need to store how far we have
@@ -866,7 +863,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
break;
case QV4::CompiledData::BuiltinType::InvalidBuiltin:
- if (property.isList) {
+ if (property.isList()) {
// Writing such a property is not supported. Content is added through the list property
// methods.
} else {
@@ -888,18 +885,20 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
if (id < aliasCount) {
const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[id];
- if ((aliasData->flags & QV4::CompiledData::Alias::AliasPointsToPointerObject) && c == QMetaObject::ReadProperty)
- *reinterpret_cast<void **>(a[0]) = nullptr;
+ if (aliasData->hasFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject)
+ && c == QMetaObject::ReadProperty){
+ *reinterpret_cast<void **>(a[0]) = nullptr;
+ }
if (!ctxt) return -1;
- while (aliasData->aliasToLocalAlias)
+ while (aliasData->isAliasToLocalAlias())
aliasData = &compiledObject->aliasTable()[aliasData->localAliasIndex];
QQmlContext *context = ctxt->asQQmlContext();
QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context);
- QObject *target = ctxtPriv->data->idValues[aliasData->targetObjectId].data();
+ QObject *target = ctxtPriv->data->idValues[aliasData->targetObjectId()].data();
if (!target)
return -1;
@@ -1260,9 +1259,9 @@ bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex,
const int aliasId = index - propOffset() - compiledObject->nProperties;
const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[aliasId];
- while (aliasData->aliasToLocalAlias)
+ while (aliasData->isAliasToLocalAlias())
aliasData = &compiledObject->aliasTable()[aliasData->localAliasIndex];
- *target = ctxt->idValues[aliasData->targetObjectId].data();
+ *target = ctxt->idValues[aliasData->targetObjectId()].data();
if (!*target)
return false;
@@ -1290,7 +1289,7 @@ void QQmlVMEMetaObject::connectAlias(int aliasId)
}
endpoint->metaObject = this;
- endpoint->connect(&ctxt->idValues[aliasData->targetObjectId].bindings);
+ endpoint->connect(&ctxt->idValues[aliasData->targetObjectId()].bindings);
endpoint->tryConnect();
}
diff --git a/src/qml/qtqmlglobal_p.h b/src/qml/qtqmlglobal_p.h
index 7b0910fa13..76479431dc 100644
--- a/src/qml/qtqmlglobal_p.h
+++ b/src/qml/qtqmlglobal_p.h
@@ -70,4 +70,26 @@ GHS_KEEP_REFERENCE(qml_register_types_QtQml);
# define Q_QML_AUTOTEST_EXPORT
#endif
+// When doing macOS universal builds, JIT needs to be disabled for the ARM slice.
+// Because both arm and x86_64 slices are built in one clang frontend invocation
+// we need this hack to ensure each backend invocation sees the correct value
+// of the feature definition.
+
+// Unset dummy value
+#undef QT_QML_JIT_SUPPORTED_IMPL
+// Compute per-arch value and save in extra define
+#if QT_CONFIG(qml_jit) && !(defined(Q_OS_MACOS) && defined(Q_PROCESSOR_ARM))
+# define QT_QML_JIT_SUPPORTED_IMPL 1
+#else
+# define QT_QML_JIT_SUPPORTED_IMPL 0
+#endif
+// Unset original feature value
+#undef QT_FEATURE_qml_jit
+// Set new value based on previous computation
+#if QT_QML_JIT_SUPPORTED_IMPL
+# define QT_FEATURE_qml_jit 1
+#else
+# define QT_FEATURE_qml_jit -1
+#endif
+
#endif // QTQMLGLOBAL_P_H
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index 29ed62cd39..4a4e6ce12c 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -247,17 +247,20 @@ void QQmlConnectionsParser::verifyBindings(const QQmlRefPointer<QV4::ExecutableC
return;
}
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Script)
+ continue;
+
+ if (binding->type() >= QV4::CompiledData::Binding::Type_Object) {
const QV4::CompiledData::Object *target = compilationUnit->objectAt(binding->value.objectIndex);
if (!compilationUnit->stringAt(target->inheritedTypeNameIndex).isEmpty())
error(binding, QQmlConnections::tr("Connections: nested objects not allowed"));
else
error(binding, QQmlConnections::tr("Connections: syntax error"));
return;
- } if (binding->type != QV4::CompiledData::Binding::Type_Script) {
- error(binding, QQmlConnections::tr("Connections: script expected"));
- return;
}
+
+ error(binding, QQmlConnections::tr("Connections: script expected"));
+ return;
}
}
@@ -352,7 +355,7 @@ void QQmlConnections::connectSignalsToBindings()
QQmlContextData *ctxtdata = ddata ? ddata->outerContext : nullptr;
for (const QV4::CompiledData::Binding *binding : qAsConst(d->bindings)) {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script);
+ Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Script);
QString propName = d->compilationUnit->stringAt(binding->propertyNameIndex);
QQmlProperty prop(target, propName);
diff --git a/src/qml/util/qqmlpropertymap.cpp b/src/qml/util/qqmlpropertymap.cpp
index 82f048d9d9..5c4cd7352a 100644
--- a/src/qml/util/qqmlpropertymap.cpp
+++ b/src/qml/util/qqmlpropertymap.cpp
@@ -370,3 +370,5 @@ QQmlPropertyMap::QQmlPropertyMap(const QMetaObject *staticMetaObject, QObject *p
*/
QT_END_NAMESPACE
+
+#include "moc_qqmlpropertymap.cpp"
diff --git a/src/qmldebug/qmldebug.pro b/src/qmldebug/qmldebug.pro
index ac3f3bf3bf..fd15c9054a 100644
--- a/src/qmldebug/qmldebug.pro
+++ b/src/qmldebug/qmldebug.pro
@@ -16,6 +16,7 @@ SOURCES += \
qqmlprofilerclient.cpp \
qqmlprofilerevent.cpp \
qqmlprofilereventlocation.cpp \
+ qqmlprofilereventreceiver.cpp \
qqmlprofilereventtype.cpp \
qqmlprofilertypedevent.cpp \
qv4debugclient.cpp
diff --git a/src/qmldebug/qqmldebugclient.cpp b/src/qmldebug/qqmldebugclient.cpp
index 03123cc6e0..13785dd6db 100644
--- a/src/qmldebug/qqmldebugclient.cpp
+++ b/src/qmldebug/qqmldebugclient.cpp
@@ -123,3 +123,5 @@ void QQmlDebugClient::messageReceived(const QByteArray &message)
}
QT_END_NAMESPACE
+
+#include "moc_qqmldebugclient_p.cpp"
diff --git a/src/qmldebug/qqmldebugmessageclient.cpp b/src/qmldebug/qqmldebugmessageclient.cpp
index 0892404194..ce7a3cb2bb 100644
--- a/src/qmldebug/qqmldebugmessageclient.cpp
+++ b/src/qmldebug/qqmldebugmessageclient.cpp
@@ -88,3 +88,5 @@ void QQmlDebugMessageClient::messageReceived(const QByteArray &data)
}
QT_END_NAMESPACE
+
+#include "moc_qqmldebugmessageclient_p.cpp"
diff --git a/src/qmldebug/qqmldebugtranslationclient.cpp b/src/qmldebug/qqmldebugtranslationclient.cpp
index 1fd0748fa0..486fc3316e 100644
--- a/src/qmldebug/qqmldebugtranslationclient.cpp
+++ b/src/qmldebug/qqmldebugtranslationclient.cpp
@@ -74,3 +74,5 @@ void QQmlDebugTranslationClient::triggerLanguage(const QUrl &url, const QString
}
QT_END_NAMESPACE
+
+#include "moc_qqmldebugtranslationclient_p.cpp"
diff --git a/src/qmldebug/qqmlenginedebugclient.cpp b/src/qmldebug/qqmlenginedebugclient.cpp
index 0ca3f573d9..fd467337d8 100644
--- a/src/qmldebug/qqmlenginedebugclient.cpp
+++ b/src/qmldebug/qqmlenginedebugclient.cpp
@@ -566,3 +566,5 @@ qint32 QQmlEngineDebugClient::getId()
}
QT_END_NAMESPACE
+
+#include "moc_qqmlenginedebugclient_p.cpp"
diff --git a/src/qmldebug/qqmlinspectorclient.cpp b/src/qmldebug/qqmlinspectorclient.cpp
index 1de52bd0c1..a3f5c68f0d 100644
--- a/src/qmldebug/qqmlinspectorclient.cpp
+++ b/src/qmldebug/qqmlinspectorclient.cpp
@@ -148,3 +148,5 @@ void QQmlInspectorClient::messageReceived(const QByteArray &message)
}
QT_END_NAMESPACE
+
+#include "moc_qqmlinspectorclient_p.cpp"
diff --git a/src/qmldebug/qqmlpreviewclient.cpp b/src/qmldebug/qqmlpreviewclient.cpp
index 60937b9cfd..3a76476700 100644
--- a/src/qmldebug/qqmlpreviewclient.cpp
+++ b/src/qmldebug/qqmlpreviewclient.cpp
@@ -137,3 +137,5 @@ void QQmlPreviewClient::triggerLanguage(const QUrl &url, const QString &locale)
}
QT_END_NAMESPACE
+
+#include "moc_qqmlpreviewclient_p.cpp"
diff --git a/src/qmldebug/qqmlprofilereventreceiver.cpp b/src/qmldebug/qqmlprofilereventreceiver.cpp
new file mode 100644
index 0000000000..cb88f821f8
--- /dev/null
+++ b/src/qmldebug/qqmlprofilereventreceiver.cpp
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml 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 "qqmlprofilereventreceiver_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQmlProfilerEventReceiver::~QQmlProfilerEventReceiver()
+ = default;
+
+QT_END_NAMESPACE
+
+#include "moc_qqmlprofilereventreceiver_p.cpp"
diff --git a/src/qmldebug/qqmlprofilereventreceiver_p.h b/src/qmldebug/qqmlprofilereventreceiver_p.h
index defe64a42e..45d9abf71d 100644
--- a/src/qmldebug/qqmlprofilereventreceiver_p.h
+++ b/src/qmldebug/qqmlprofilereventreceiver_p.h
@@ -62,7 +62,8 @@ class QQmlProfilerEventReceiver : public QObject
{
Q_OBJECT
public:
- QQmlProfilerEventReceiver(QObject *parent = nullptr) : QObject(parent) {}
+ explicit QQmlProfilerEventReceiver(QObject *parent = nullptr) : QObject(parent) {}
+ ~QQmlProfilerEventReceiver() override;
virtual int numLoadedEventTypes() const = 0;
virtual void addEventType(const QQmlProfilerEventType &type) = 0;
diff --git a/src/qmldebug/qv4debugclient.cpp b/src/qmldebug/qv4debugclient.cpp
index 76c2f1ebea..127e4a405e 100644
--- a/src/qmldebug/qv4debugclient.cpp
+++ b/src/qmldebug/qv4debugclient.cpp
@@ -576,3 +576,5 @@ QByteArray QV4DebugClientPrivate::packMessage(const QByteArray &type, const QJso
}
QT_END_NAMESPACE
+
+#include "moc_qv4debugclient_p.cpp"
diff --git a/src/qmlmodels/qqmlabstractdelegatecomponent.cpp b/src/qmlmodels/qqmlabstractdelegatecomponent.cpp
index 1058d87485..869c6a4fa9 100644
--- a/src/qmlmodels/qqmlabstractdelegatecomponent.cpp
+++ b/src/qmlmodels/qqmlabstractdelegatecomponent.cpp
@@ -59,3 +59,5 @@ QVariant QQmlAbstractDelegateComponent::value(QQmlAdaptorModel *adaptorModel, in
}
QT_END_NAMESPACE
+
+#include "moc_qqmlabstractdelegatecomponent_p.cpp"
diff --git a/src/qmlmodels/qqmladaptormodel.cpp b/src/qmlmodels/qqmladaptormodel.cpp
index 2126ad3dc5..991a5c9e08 100644
--- a/src/qmlmodels/qqmladaptormodel.cpp
+++ b/src/qmlmodels/qqmladaptormodel.cpp
@@ -962,30 +962,36 @@ QQmlAdaptorModel::~QQmlAdaptorModel()
accessors->cleanup(*this);
}
-void QQmlAdaptorModel::setModel(const QVariant &variant, QObject *parent, QQmlEngine *engine)
+void QQmlAdaptorModel::setModel(const QVariant &variant, QObject *, QQmlEngine *engine)
{
accessors->cleanup(*this);
list.setList(variant, engine);
+ modelStrongReference.clear();
if (QObject *object = qvariant_cast<QObject *>(list.list())) {
- setObject(object, parent);
+ if (QQmlData *ddata = QQmlData::get(object))
+ modelStrongReference = ddata->jsWrapper;
+ setObject(object);
if (qobject_cast<QAbstractItemModel *>(object))
accessors = new VDMAbstractItemModelDataType(this);
else
accessors = new VDMObjectDelegateDataType;
} else if (list.type() == QQmlListAccessor::ListProperty) {
- setObject(static_cast<const QQmlListReference *>(variant.constData())->object(), parent);
+ auto object = static_cast<const QQmlListReference *>(variant.constData())->object();
+ if (QQmlData *ddata = QQmlData::get(object))
+ modelStrongReference = ddata->jsWrapper;
+ setObject(object);
accessors = new VDMObjectDelegateDataType;
} else if (list.type() == QQmlListAccessor::ObjectList) {
- setObject(nullptr, parent);
+ setObject(nullptr);
accessors = new VDMObjectDelegateDataType;
} else if (list.type() != QQmlListAccessor::Invalid
&& list.type() != QQmlListAccessor::Instance) { // Null QObject
- setObject(nullptr, parent);
+ setObject(nullptr);
accessors = new VDMListDelegateDataType;
} else {
- setObject(nullptr, parent);
+ setObject(nullptr);
accessors = &qt_vdm_null_accessors;
}
}
diff --git a/src/qmlmodels/qqmladaptormodel_p.h b/src/qmlmodels/qqmladaptormodel_p.h
index ba54c864c6..4dbb6ed54e 100644
--- a/src/qmlmodels/qqmladaptormodel_p.h
+++ b/src/qmlmodels/qqmladaptormodel_p.h
@@ -70,7 +70,7 @@ class QQmlDelegateModel;
class QQmlDelegateModelItem;
class QQmlDelegateModelItemMetaType;
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlAdaptorModel : public QQmlStrongJSQObjectReference<QObject>
+class Q_QMLMODELS_PRIVATE_EXPORT QQmlAdaptorModel : public QQmlGuard<QObject>
{
public:
class Accessors
@@ -114,6 +114,10 @@ public:
const Accessors *accessors;
QPersistentModelIndex rootIndex;
QQmlListAccessor list;
+ // we need to ensure that a JS created model does not get gced, but cannot
+ // arbitrarily set the parent (using QQmlStrongJSQObjectReference) of QObject based models,
+ // as that causes issues with singletons
+ QV4::PersistentValue modelStrongReference;
int modelItemRevision = 0;
diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp
index 2079a8ed04..4fcff70de6 100644
--- a/src/qmlmodels/qqmldelegatemodel.cpp
+++ b/src/qmlmodels/qqmldelegatemodel.cpp
@@ -258,7 +258,7 @@ QQmlDelegateModel::~QQmlDelegateModel()
{
Q_D(QQmlDelegateModel);
d->disconnectFromAbstractItemModel();
- d->m_adaptorModel.setObject(nullptr, this);
+ d->m_adaptorModel.setObject(nullptr);
for (QQmlDelegateModelItem *cacheItem : qAsConst(d->m_cache)) {
if (cacheItem->object) {
@@ -1728,6 +1728,7 @@ void QQmlDelegateModel::_q_itemsRemoved(int index, int count)
return;
d->m_count -= count;
+ Q_ASSERT(d->m_count >= 0);
const QList<QQmlDelegateModelItem *> cache = d->m_cache;
//Prevents items being deleted in remove loop
for (QQmlDelegateModelItem *item : cache)
@@ -3922,4 +3923,6 @@ QV4::ReturnedValue QQmlDelegateModelEngineData::array(QV4::ExecutionEngine *v4,
QT_END_NAMESPACE
+#include "moc_qqmldelegatemodel_p_p.cpp"
+
#include "moc_qqmldelegatemodel_p.cpp"
diff --git a/src/qmlmodels/qqmlinstantiator.cpp b/src/qmlmodels/qqmlinstantiator.cpp
index 3a0d746eb6..1d5249d4c0 100644
--- a/src/qmlmodels/qqmlinstantiator.cpp
+++ b/src/qmlmodels/qqmlinstantiator.cpp
@@ -147,7 +147,7 @@ void QQmlInstantiatorPrivate::_q_modelUpdated(const QQmlChangeSet &changeSet, bo
{
Q_Q(QQmlInstantiator);
- if (!componentComplete || effectiveReset)
+ if (!componentComplete || effectiveReset || !active)
return;
if (reset) {
diff --git a/src/qmlmodels/qqmllistcompositor_p.h b/src/qmlmodels/qqmllistcompositor_p.h
index 6639726850..ccd565a5bd 100644
--- a/src/qmlmodels/qqmllistcompositor_p.h
+++ b/src/qmlmodels/qqmllistcompositor_p.h
@@ -311,6 +311,10 @@ Q_DECLARE_TYPEINFO(QQmlListCompositor::Insert, Q_PRIMITIVE_TYPE);
inline QQmlListCompositor::iterator::iterator() {}
+QT_WARNING_PUSH
+// GCC isn't wrong, as groupCount is public in iterator, but we tried Q_ASSUME(),
+// right in front of the loops, and it didn't help, so we disable the warning:
+QT_WARNING_DISABLE_GCC("-Warray-bounds")
inline QQmlListCompositor::iterator::iterator(
Range *range, int offset, Group group, int groupCount)
: range(range)
@@ -338,6 +342,7 @@ inline void QQmlListCompositor::iterator::decrementIndexes(int difference, uint
index[i] -= difference;
}
}
+QT_WARNING_POP // -Warray-bounds
inline QQmlListCompositor::insert_iterator::insert_iterator(
Range *range, int offset, Group group, int groupCount)
diff --git a/src/qmlmodels/qqmllistmodel.cpp b/src/qmlmodels/qqmllistmodel.cpp
index e392c9e323..c181cf15c7 100644
--- a/src/qmlmodels/qqmllistmodel.cpp
+++ b/src/qmlmodels/qqmllistmodel.cpp
@@ -2719,7 +2719,7 @@ void QQmlListModel::sync()
bool QQmlListModelParser::verifyProperty(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding)
{
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ if (binding->type() >= QV4::CompiledData::Binding::Type_Object) {
const quint32 targetObjectIndex = binding->value.objectIndex;
const QV4::CompiledData::Object *target = compilationUnit->objectAt(targetObjectIndex);
QString objName = compilationUnit->stringAt(target->inheritedTypeNameIndex);
@@ -2747,7 +2747,7 @@ bool QQmlListModelParser::verifyProperty(const QQmlRefPointer<QV4::ExecutableCom
if (!verifyProperty(compilationUnit, binding))
return false;
}
- } else if (binding->type == QV4::CompiledData::Binding::Type_Script) {
+ } else if (binding->type() == QV4::CompiledData::Binding::Type_Script) {
QString scriptStr = compilationUnit->bindingValueAsScriptString(binding);
if (!binding->isFunctionExpression() && !definesEmptyList(scriptStr)) {
QByteArray script = scriptStr.toUtf8();
@@ -2770,7 +2770,8 @@ bool QQmlListModelParser::applyProperty(
const QString elementName = compilationUnit->stringAt(binding->propertyNameIndex);
bool roleSet = false;
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
+ if (bindingType >= QV4::CompiledData::Binding::Type_Object) {
const quint32 targetObjectIndex = binding->value.objectIndex;
const QV4::CompiledData::Object *target = compilationUnit->objectAt(targetObjectIndex);
@@ -2803,13 +2804,13 @@ bool QQmlListModelParser::applyProperty(
value = QVariant::fromValue<const QV4::CompiledData::Binding*>(binding);
} else if (binding->evaluatesToString()) {
value = compilationUnit->bindingValueAsString(binding);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ } else if (bindingType == QV4::CompiledData::Binding::Type_Number) {
value = compilationUnit->bindingValueAsNumber(binding);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
+ } else if (bindingType == QV4::CompiledData::Binding::Type_Boolean) {
value = binding->valueAsBoolean();
- } else if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ } else if (bindingType == QV4::CompiledData::Binding::Type_Null) {
value = QVariant::fromValue(nullptr);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Script) {
+ } else if (bindingType == QV4::CompiledData::Binding::Type_Script) {
QString scriptStr = compilationUnit->bindingValueAsScriptString(binding);
if (definesEmptyList(scriptStr)) {
const ListLayout::Role &role = model->getOrCreateListRole(elementName);
@@ -2872,7 +2873,7 @@ void QQmlListModelParser::applyBindings(QObject *obj, const QQmlRefPointer<QV4::
bool setRoles = false;
for (const QV4::CompiledData::Binding *binding : bindings) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object)
+ if (binding->type() != QV4::CompiledData::Binding::Type_Object)
continue;
setRoles |= applyProperty(compilationUnit, binding, rv->m_listModel, /*outter element index*/-1);
}
@@ -2942,4 +2943,6 @@ bool QQmlListModelParser::definesEmptyList(const QString &s)
QT_END_NAMESPACE
+#include "moc_qqmllistmodel_p_p.cpp"
+
#include "moc_qqmllistmodel_p.cpp"
diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp
index 150db84533..c0cf3e469c 100644
--- a/src/qmltest/quicktest.cpp
+++ b/src/qmltest/quicktest.cpp
@@ -309,7 +309,7 @@ private:
if (!object) // Start at root of compilation unit if not enumerating a specific child
object = compilationUnit->objectAt(0);
- if (object->flags & Object::IsInlineComponentRoot)
+ if (object->hasFlag(Object::IsInlineComponentRoot))
return result;
if (const auto superTypeUnit = compilationUnit->resolvedTypes.value(
@@ -325,13 +325,13 @@ private:
// Look for override of name in this type
for (auto binding = object->bindingsBegin(); binding != object->bindingsEnd(); ++binding) {
if (compilationUnit->stringAt(binding->propertyNameIndex) == QLatin1String("name")) {
- if (binding->type == QV4::CompiledData::Binding::Type_String) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_String) {
result.testCaseName = compilationUnit->stringAt(binding->stringIndex);
} else {
QQmlError error;
error.setUrl(compilationUnit->url());
- error.setLine(binding->location.line);
- error.setColumn(binding->location.column);
+ error.setLine(binding->location.line());
+ error.setColumn(binding->location.column());
error.setDescription(QStringLiteral("the 'name' property of a TestCase must be a literal string"));
result.errors << error;
}
@@ -355,7 +355,7 @@ private:
}
for (auto binding = object->bindingsBegin(); binding != object->bindingsEnd(); ++binding) {
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Object) {
const Object *child = compilationUnit->objectAt(binding->value.objectIndex);
result << enumerateTestCases(compilationUnit, child);
}
@@ -650,3 +650,5 @@ int quick_test_main_with_setup(int argc, char **argv, const char *name, const ch
}
QT_END_NAMESPACE
+
+#include "moc_quicktest_p.cpp"
diff --git a/src/qmltest/quicktestresult.cpp b/src/qmltest/quicktestresult.cpp
index f3a6fea193..6a9dc335ff 100644
--- a/src/qmltest/quicktestresult.cpp
+++ b/src/qmltest/quicktestresult.cpp
@@ -773,7 +773,8 @@ QObject *QuickTestResult::grabImage(QQuickItem *item)
if (item && item->window()) {
QQuickWindow *window = item->window();
QImage grabbed = window->grabWindow();
- QRectF rf(item->x(), item->y(), item->width(), item->height());
+ const auto dpi = grabbed.devicePixelRatio();
+ QRectF rf(item->x() * dpi, item->y() * dpi, item->width() * dpi, item->height() * dpi);
rf = rf.intersected(QRectF(0, 0, grabbed.width(), grabbed.height()));
QObject *o = new QuickTestImageObject(grabbed.copy(rf.toAlignedRect()));
QQmlEngine::setContextForObject(o, qmlContext(this));
diff --git a/src/qmltyperegistrar/qmltypes.prf b/src/qmltyperegistrar/qmltypes.prf
index 2cc0027b7e..471bb6e3b0 100644
--- a/src/qmltyperegistrar/qmltypes.prf
+++ b/src/qmltyperegistrar/qmltypes.prf
@@ -81,12 +81,18 @@ qmltyperegistrar_compiler.output = $$TYPEREGISTRATIONS
qmltyperegistrar_compiler.variable_out = SOURCES
qmltyperegistrar_compiler.name = Automatic QML type registration
qmltyperegistrar_compiler.dependency_type = TYPE_C
-
-qmltyperegistrar_qmltypes.input = METATYPES_JSON
-qmltyperegistrar_qmltypes.depends = $$TYPEREGISTRATIONS
-qmltyperegistrar_qmltypes.output = $$QMLTYPES_FILENAME
-qmltyperegistrar_qmltypes.CONFIG = no_link
-qmltyperegistrar_qmltypes.commands = $$escape_expand(\\n) # force creation of rule
+QMAKE_EXTRA_COMPILERS += qmltyperegistrar_compiler
+
+!contains(TEMPLATE, "vc.*") { # work around QTBUG-91033
+ # Create a fake extra compiler to announce that we generate $$QMLTYPES_FILENAME.
+ # This allows us to use $$QMLTYPES_FILENAME as input in other extra compilers.
+ qmltyperegistrar_qmltypes.input = METATYPES_JSON
+ qmltyperegistrar_qmltypes.depends = $$TYPEREGISTRATIONS
+ qmltyperegistrar_qmltypes.output = $$QMLTYPES_FILENAME
+ qmltyperegistrar_qmltypes.CONFIG = no_link
+ qmltyperegistrar_qmltypes.commands = $$escape_expand(\\n) # force creation of rule
+ QMAKE_EXTRA_COMPILERS += qmltyperegistrar_qmltypes
+}
install_qmltypes {
INSTALL_QML_FILES = false
@@ -109,5 +115,3 @@ install_qmltypes {
else: COPIES += do_install_qmltypes
}
}
-
-QMAKE_EXTRA_COMPILERS += qmltyperegistrar_compiler qmltyperegistrar_qmltypes
diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp
index 85719fdc80..ae1954ae8d 100644
--- a/src/quick/accessible/qaccessiblequickitem.cpp
+++ b/src/quick/accessible/qaccessiblequickitem.cpp
@@ -177,6 +177,11 @@ QList<QQuickItem *> QAccessibleQuickItem::childItems() const
return accessibleUnignoredChildren(item());
}
+static bool isTextRole(QAccessible::Role role)
+{
+ return role == QAccessible::EditableText || role == QAccessible::StaticText;
+}
+
QAccessible::State QAccessibleQuickItem::state() const
{
QQuickAccessibleAttached *attached = QQuickAccessibleAttached::attachedProperties(item());
@@ -194,7 +199,7 @@ QAccessible::State QAccessibleQuickItem::state() const
state.offscreen = true;
if ((role() == QAccessible::CheckBox || role() == QAccessible::RadioButton) && object()->property("checked").toBool())
state.checked = true;
- if (item()->activeFocusOnTab() || role() == QAccessible::EditableText)
+ if (item()->activeFocusOnTab() || isTextRole(role()))
state.focusable = true;
if (item()->hasActiveFocus())
state.focused = true;
diff --git a/src/quick/doc/images/containmentMask-circle.gif b/src/quick/doc/images/containmentMask-circle.gif
new file mode 100644
index 0000000000..80abce625f
--- /dev/null
+++ b/src/quick/doc/images/containmentMask-circle.gif
Binary files differ
diff --git a/src/quick/doc/images/containmentMask-shape.gif b/src/quick/doc/images/containmentMask-shape.gif
new file mode 100644
index 0000000000..e7989352eb
--- /dev/null
+++ b/src/quick/doc/images/containmentMask-shape.gif
Binary files differ
diff --git a/src/quick/doc/snippets/pointerHandlers/hoverModifiers.qml b/src/quick/doc/snippets/pointerHandlers/hoverModifiers.qml
new file mode 100644
index 0000000000..b8a378ddcf
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/hoverModifiers.qml
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Rectangle {
+ width: 150; height: 50; radius: 3
+ color: control.hovered ? "goldenrod" : shift.hovered ? "wheat" : "beige"
+
+ HoverHandler {
+ id: control
+ acceptedModifiers: Qt.ControlModifier
+ cursorShape: Qt.PointingHandCursor
+ }
+
+ HoverHandler {
+ id: shift
+ acceptedModifiers: Qt.ShiftModifier
+ cursorShape: Qt.CrossCursor
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/hoverMouseOrStylus.qml b/src/quick/doc/snippets/pointerHandlers/hoverMouseOrStylus.qml
new file mode 100644
index 0000000000..6bd6a40b1a
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/hoverMouseOrStylus.qml
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Rectangle {
+ width: 150; height: 50; radius: 3
+ color: mouse.hovered ? "goldenrod" : stylus.hovered ? "tomato" : "wheat"
+
+ HoverHandler {
+ id: stylus
+ acceptedDevices: PointerDevice.Stylus
+ cursorShape: Qt.CrossCursor
+ }
+
+ HoverHandler {
+ id: mouse
+ acceptedDevices: PointerDevice.Mouse
+ cursorShape: Qt.PointingHandCursor
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/hoverStylusOrEraser.qml b/src/quick/doc/snippets/pointerHandlers/hoverStylusOrEraser.qml
new file mode 100644
index 0000000000..5d82158baf
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/hoverStylusOrEraser.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Rectangle {
+ id: rect
+ width: 150; height: 150
+
+ HoverHandler {
+ id: stylus
+ acceptedPointerTypes: PointerDevice.Pen
+ cursorShape: Qt.CrossCursor
+ }
+
+ HoverHandler {
+ id: eraser
+ acceptedPointerTypes: PointerDevice.Eraser
+ cursorShape: Qt.BlankCursor
+ target: Image {
+ parent: rect
+ source: "images/cursor-eraser.png"
+ visible: eraser.hovered
+ x: eraser.point.position.x
+ y: eraser.point.position.y - 32
+ }
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/images/cursor-eraser.png b/src/quick/doc/snippets/pointerHandlers/images/cursor-eraser.png
new file mode 100644
index 0000000000..e5488a89f2
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/images/cursor-eraser.png
Binary files differ
diff --git a/src/quick/doc/snippets/qml/item/containmentMask-circle-js.qml b/src/quick/doc/snippets/qml/item/containmentMask-circle-js.qml
new file mode 100644
index 0000000000..2d97bcdafa
--- /dev/null
+++ b/src/quick/doc/snippets/qml/item/containmentMask-circle-js.qml
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQml 2.12
+import QtQuick 2.12
+
+//![0]
+Rectangle {
+ id: circle
+ width: 100; height: width
+ radius: width / 2
+ color: tapHandler.pressed ? "tomato" : hoverHandler.hovered ? "darkgray" : "lightgray"
+
+ TapHandler { id: tapHandler }
+ HoverHandler { id: hoverHandler }
+
+ containmentMask: QtObject {
+ property alias radius: circle.radius
+ function contains(point: point) : bool {
+ return (Math.pow(point.x - radius, 2) + Math.pow(point.y - radius, 2)) < Math.pow(radius, 2)
+ }
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/qml/item/containmentMask-shape.qml b/src/quick/doc/snippets/qml/item/containmentMask-shape.qml
new file mode 100644
index 0000000000..a3da217e73
--- /dev/null
+++ b/src/quick/doc/snippets/qml/item/containmentMask-shape.qml
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import QtQuick.Shapes 1.12
+
+//![0]
+Rectangle {
+ width: 90; height: 100
+ color: hoverHandler.hovered ? "wheat" : "lightgray"
+ containmentMask: shape
+
+ HoverHandler { id: hoverHandler }
+
+ Shape {
+ id: shape
+ containsMode: Shape.FillContains
+
+ ShapePath {
+ fillColor: "lightsteelblue"
+ startX: 10; startY: 20
+ PathArc {
+ x: 10; y: 80
+ radiusX: 40; radiusY: 40
+ useLargeArc: true
+ }
+ PathLine {
+ x: 10; y: 20
+ }
+ }
+ }
+}
+//![0]
diff --git a/src/quick/doc/src/concepts/input/focus.qdoc b/src/quick/doc/src/concepts/input/focus.qdoc
index 9862489f42..21f5f0e225 100644
--- a/src/quick/doc/src/concepts/input/focus.qdoc
+++ b/src/quick/doc/src/concepts/input/focus.qdoc
@@ -196,7 +196,7 @@ property. As the \l ListView is a focus scope, this doesn't affect the
rest of the application. However, if the \l ListView itself has
active focus this causes the delegate itself to receive active focus.
In this example, the root type of the delegate is also a focus scope,
-which in turn gives active focus to the \c {Text} type that actually performs
+which in turn gives active focus to the \l {TextInput} type that actually performs
the work of handling the \c {Return} key.
All of the QML view classes, such as \l PathView and \l GridView, behave
diff --git a/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc b/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
index abfff7cc11..8cd51a50c6 100644
--- a/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
+++ b/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
@@ -52,11 +52,16 @@ options that align with the latest UI design trends. If these UI controls do not
satisfy your application's needs, only then it is recommended to create a
custom control.
+You can use the controls when you design UIs in Qt Design Studio. In addition,
+it provides timeline-based animations, visual effects, layouts, and a
+live-preview for prototyping applications.
\section2 Related Information
\list
\li \l{Qt Quick Controls}
+\li \l{Customizing Qt Quick Controls}
\li \l{Qt Quick}
+\li \l{Qt Design Studio Manual}
\endlist
\omit
@@ -146,7 +151,7 @@ specific file managed by the resource system. For example, if we wanted to give
\li \l{The Qt Resource System}
\endlist
-\section1 Separate UI from Logic
+\section1 Separate UI from Business Logic
One of the key goals that most application developers want to achieve is to
create a maintainable application. One of the ways to achieve this goal is
@@ -162,8 +167,8 @@ reasons why an application's UI should be written in QML:
\li JavaScript can easily be used in QML to respond to events.
\endlist
-Being a strongly typed language, C++ is best suited for an application's logic.
-Typically, such code performs tasks such as complex calculations
+Being a strongly typed language, C++ is best suited for an application's
+business logic. Typically, such code performs tasks such as complex calculations
or data processing, which are faster in C++ than QML.
Qt offers various approaches to integrate QML and C++ code in an application.
@@ -326,6 +331,22 @@ see \l {Choosing the Correct Integration Method Between C++ and QML}.
\li \l{Qt Quick Controls - Chat Tutorial}{Chat application tutorial}
\endlist
+\section1 Using Qt Design Studio
+
+Qt Design Studio uses UI files that have the filename extension \e {.ui.qml}
+to separate the visual parts of the UI from the UI logic you implement in
+\e {.qml} files. You should edit UI files only in the \uicontrol {2D} view in
+Qt Design Studio. If you use some other tool to add code that Qt Design Studio
+does not support, it displays error messages. Fix the errors to enable visual
+editing of the UI files again. Typically, you should move the unsupported code
+to a \e {.qml} file.
+
+\section2 Related Information
+
+\list
+ \li \l{Qt Design Studio: UI Files}
+\endlist
+
\section1 Using Qt Quick Layouts
Qt offers Qt Quick Layouts to arrange Qt Quick items visually in a layout.
diff --git a/src/quick/handlers/qquickdragaxis.cpp b/src/quick/handlers/qquickdragaxis.cpp
index 88470c8a7d..806b5d705a 100644
--- a/src/quick/handlers/qquickdragaxis.cpp
+++ b/src/quick/handlers/qquickdragaxis.cpp
@@ -76,3 +76,5 @@ void QQuickDragAxis::setEnabled(bool enabled)
}
QT_END_NAMESPACE
+
+#include "moc_qquickdragaxis_p.cpp"
diff --git a/src/quick/handlers/qquickdraghandler.cpp b/src/quick/handlers/qquickdraghandler.cpp
index 492897b68b..b9a2c183c2 100644
--- a/src/quick/handlers/qquickdraghandler.cpp
+++ b/src/quick/handlers/qquickdraghandler.cpp
@@ -343,3 +343,5 @@ void QQuickDragHandler::setTranslation(const QVector2D &trans)
*/
QT_END_NAMESPACE
+
+#include "moc_qquickdraghandler_p.cpp"
diff --git a/src/quick/handlers/qquickhandlerpoint.cpp b/src/quick/handlers/qquickhandlerpoint.cpp
index 72efdfd0f4..7103206470 100644
--- a/src/quick/handlers/qquickhandlerpoint.cpp
+++ b/src/quick/handlers/qquickhandlerpoint.cpp
@@ -348,3 +348,5 @@ void QQuickHandlerPoint::reset(const QVector<QQuickHandlerPoint> &points)
*/
QT_END_NAMESPACE
+
+#include "moc_qquickhandlerpoint_p.cpp"
diff --git a/src/quick/handlers/qquickhoverhandler.cpp b/src/quick/handlers/qquickhoverhandler.cpp
index b12d85784a..a65730607a 100644
--- a/src/quick/handlers/qquickhoverhandler.cpp
+++ b/src/quick/handlers/qquickhoverhandler.cpp
@@ -85,8 +85,11 @@ QQuickHoverHandler::~QQuickHoverHandler()
void QQuickHoverHandler::componentComplete()
{
- parentItem()->setAcceptHoverEvents(true);
- QQuickItemPrivate::get(parentItem())->setHasHoverInChild(true);
+ QQuickSinglePointHandler::componentComplete();
+ if (auto par = parentItem()) {
+ par->setAcceptHoverEvents(true);
+ QQuickItemPrivate::get(par)->setHasHoverInChild(true);
+ }
}
bool QQuickHoverHandler::wantsPointerEvent(QQuickPointerEvent *event)
@@ -124,6 +127,13 @@ void QQuickHoverHandler::handleEventPoint(QQuickEventPoint *point)
setPassiveGrab(point);
}
+void QQuickHoverHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point)
+{
+ QQuickSinglePointHandler::onGrabChanged(grabber, transition, point);
+ if (grabber == this && transition == QQuickEventPoint::CancelGrabPassive)
+ setHovered(false);
+}
+
/*!
\qmlproperty bool QtQuick::HoverHandler::hovered
\readonly
@@ -144,6 +154,98 @@ void QQuickHoverHandler::setHovered(bool hovered)
}
/*!
+ \internal
+ \qmlproperty flags QtQuick::HoverHandler::acceptedButtons
+
+ This property is not used in HoverHandler.
+*/
+
+/*!
+ \qmlproperty flags QtQuick::HoverHandler::acceptedDevices
+
+ The types of pointing devices that can activate the pointer handler.
+
+ By default, this property is set to
+ \l{QInputDevice::DeviceType}{PointerDevice.AllDevices}.
+ If you set it to an OR combination of device types, it will ignore pointer
+ events from the non-matching devices.
+
+ For example, an item could be made to respond to mouse hover in one way,
+ and stylus hover in another way, with two handlers:
+
+ \snippet pointerHandlers/hoverMouseOrStylus.qml 0
+
+ The available device types are as follows:
+
+ \value PointerDevice.Mouse A mouse.
+ \value PointerDevice.TouchScreen A touchscreen.
+ \value PointerDevice.TouchPad A touchpad or trackpad.
+ \value PointerDevice.Stylus A stylus on a graphics tablet.
+ \value PointerDevice.Airbrush An airbrush on a graphics tablet.
+ \value PointerDevice.Puck A digitizer with crosshairs, on a graphics tablet.
+ \value PointerDevice.AllDevices Any type of pointing device.
+
+ \sa QInputDevice::DeviceType
+*/
+
+/*!
+ \qmlproperty flags QtQuick::HoverHandler::acceptedPointerTypes
+
+ The types of pointing instruments (generic, stylus, eraser, and so on)
+ that can activate the pointer handler.
+
+ By default, this property is set to
+ \l {QPointingDevice::PointerType} {PointerDevice.AllPointerTypes}.
+ If you set it to an OR combination of device types, it will ignore events
+ from non-matching events.
+
+ For example, you could provide feedback by changing the cursor depending on
+ whether a stylus or eraser is hovering over a graphics tablet:
+
+ \snippet pointerHandlers/hoverStylusOrEraser.qml 0
+
+ The available pointer types are as follows:
+
+ \value PointerDevice.Generic A mouse or a device that emulates a mouse.
+ \value PointerDevice.Finger A finger on a touchscreen (hover detection is unlikely).
+ \value PointerDevice.Pen A stylus on a graphics tablet.
+ \value PointerDevice.Eraser An eraser on a graphics tablet.
+ \value PointerDevice.Cursor A digitizer with crosshairs, on a graphics tablet.
+ \value PointerDevice.AllPointerTypes Any type of pointing device.
+
+ \sa QPointingDevice::PointerType
+*/
+
+/*!
+ \qmlproperty flags QtQuick::HoverHandler::acceptedModifiers
+
+ If this property is set, a hover event is handled only if the given keyboard
+ modifiers are pressed. The event is ignored without the modifiers.
+
+ This property is set to \c Qt.KeyboardModifierMask by default, resulting
+ in handling hover events regardless of any modifier keys.
+
+ For example, an \l[QML]{Item} could have two handlers of the same type, one
+ of which is enabled only if the required keyboard modifiers are pressed:
+
+ \snippet pointerHandlers/hoverModifiers.qml 0
+
+ The available modifiers are as follows:
+
+ \value Qt.NoModifier No modifier key is allowed.
+ \value Qt.ShiftModifier A Shift key on the keyboard must be pressed.
+ \value Qt.ControlModifier A Ctrl key on the keyboard must be pressed.
+ \value Qt.AltModifier An Alt key on the keyboard must be pressed.
+ \value Qt.MetaModifier A Meta key on the keyboard must be pressed.
+ \value Qt.KeypadModifier A keypad button must be pressed.
+ \value Qt.GroupSwitchModifier A Mode_switch key on the keyboard must be pressed.
+ X11 only (unless activated on Windows by a command line argument).
+ \value Qt.KeyboardModifierMask The handler ignores modifier keys.
+
+ \sa Qt::KeyboardModifier
+*/
+
+/*!
\since 5.15
\qmlproperty Qt::CursorShape QtQuick::HoverHandler::cursorShape
This property holds the cursor shape that will appear whenever
@@ -192,3 +294,5 @@ void QQuickHoverHandler::setHovered(bool hovered)
*/
QT_END_NAMESPACE
+
+#include "moc_qquickhoverhandler_p.cpp"
diff --git a/src/quick/handlers/qquickhoverhandler_p.h b/src/quick/handlers/qquickhoverhandler_p.h
index 313b87217c..426372d162 100644
--- a/src/quick/handlers/qquickhoverhandler_p.h
+++ b/src/quick/handlers/qquickhoverhandler_p.h
@@ -78,6 +78,7 @@ protected:
void componentComplete() override;
bool wantsPointerEvent(QQuickPointerEvent *event) override;
void handleEventPoint(QQuickEventPoint *point) override;
+ void onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point) override;
private:
void setHovered(bool hovered);
diff --git a/src/quick/handlers/qquickmultipointhandler.cpp b/src/quick/handlers/qquickmultipointhandler.cpp
index 2a9ecd341c..443cf4ffbc 100644
--- a/src/quick/handlers/qquickmultipointhandler.cpp
+++ b/src/quick/handlers/qquickmultipointhandler.cpp
@@ -436,3 +436,5 @@ QMetaProperty &QQuickMultiPointHandlerPrivate::yMetaProperty() const
}
QT_END_NAMESPACE
+
+#include "moc_qquickmultipointhandler_p.cpp"
diff --git a/src/quick/handlers/qquickpinchhandler.cpp b/src/quick/handlers/qquickpinchhandler.cpp
index bf43d56a93..16cf2c8100 100644
--- a/src/quick/handlers/qquickpinchhandler.cpp
+++ b/src/quick/handlers/qquickpinchhandler.cpp
@@ -543,6 +543,11 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
The translation of the gesture \l centroid. It is \c (0, 0) when the
gesture begins.
+
+ \note On some touchpads, such as on a \macos trackpad, native gestures do
+ not generate any translation values, and this property stays at \c (0, 0).
*/
QT_END_NAMESPACE
+
+#include "moc_qquickpinchhandler_p.cpp"
diff --git a/src/quick/handlers/qquickpointerdevicehandler.cpp b/src/quick/handlers/qquickpointerdevicehandler.cpp
index 90f31bf9fd..b7f0580648 100644
--- a/src/quick/handlers/qquickpointerdevicehandler.cpp
+++ b/src/quick/handlers/qquickpointerdevicehandler.cpp
@@ -314,3 +314,5 @@ bool QQuickPointerDeviceHandler::wantsPointerEvent(QQuickPointerEvent *event)
}
QT_END_NAMESPACE
+
+#include "moc_qquickpointerdevicehandler_p.cpp"
diff --git a/src/quick/handlers/qquickpointerhandler.cpp b/src/quick/handlers/qquickpointerhandler.cpp
index a6c18feafe..67700e04fa 100644
--- a/src/quick/handlers/qquickpointerhandler.cpp
+++ b/src/quick/handlers/qquickpointerhandler.cpp
@@ -207,9 +207,11 @@ void QQuickPointerHandler::setCursorShape(Qt::CursorShape shape)
return;
d->cursorShape = shape;
d->cursorSet = true;
- QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parentItem());
- itemPriv->hasCursorHandler = true;
- itemPriv->setHasCursorInChild(true);
+ if (auto *par = qmlobject_cast<QQuickItem *>(parent())) {
+ QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(par);
+ itemPriv->hasCursorHandler = true;
+ itemPriv->setHasCursorInChild(true);
+ }
emit cursorShapeChanged();
}
@@ -220,9 +222,11 @@ void QQuickPointerHandler::resetCursorShape()
return;
d->cursorShape = Qt::ArrowCursor;
d->cursorSet = false;
- QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parentItem());
- itemPriv->hasCursorHandler = false;
- itemPriv->setHasCursorInChild(itemPriv->hasCursor);
+ if (auto *parent = parentItem()) {
+ QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parent);
+ itemPriv->hasCursorHandler = false;
+ itemPriv->setHasCursorInChild(itemPriv->hasCursor);
+ }
emit cursorShapeChanged();
}
@@ -417,6 +421,8 @@ bool QQuickPointerHandler::approveGrabTransition(QQuickEventPoint *point, QObjec
This handler can take the exclusive grab from another handler of the same class.
\value PointerHandler.CanTakeOverFromHandlersOfDifferentType
This handler can take the exclusive grab from any kind of handler.
+ \value PointerHandler.CanTakeOverFromItems
+ This handler can take the exclusive grab from any type of Item.
\value PointerHandler.CanTakeOverFromAnything
This handler can take the exclusive grab from any type of Item or Handler.
\value PointerHandler.ApprovesTakeOverByHandlersOfSameType
@@ -457,6 +463,14 @@ void QQuickPointerHandler::classBegin()
void QQuickPointerHandler::componentComplete()
{
+ Q_D(const QQuickPointerHandler);
+ if (d->cursorSet) {
+ if (auto *parent = parentItem()) {
+ QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parent);
+ itemPriv->hasCursorHandler = true;
+ itemPriv->setHasCursorInChild(true);
+ }
+ }
}
QQuickPointerEvent *QQuickPointerHandler::currentEvent()
@@ -730,3 +744,5 @@ bool QQuickPointerHandlerPrivate::dragOverThreshold(const QQuickEventPoint *poin
}
QT_END_NAMESPACE
+
+#include "moc_qquickpointerhandler_p.cpp"
diff --git a/src/quick/handlers/qquickpointhandler.cpp b/src/quick/handlers/qquickpointhandler.cpp
index 30f62332ba..6b7b70f17a 100644
--- a/src/quick/handlers/qquickpointhandler.cpp
+++ b/src/quick/handlers/qquickpointhandler.cpp
@@ -163,3 +163,5 @@ QVector2D QQuickPointHandler::translation() const
}
QT_END_NAMESPACE
+
+#include "moc_qquickpointhandler_p.cpp"
diff --git a/src/quick/handlers/qquicksinglepointhandler.cpp b/src/quick/handlers/qquicksinglepointhandler.cpp
index b51f53b74f..d785d8c0ca 100644
--- a/src/quick/handlers/qquicksinglepointhandler.cpp
+++ b/src/quick/handlers/qquicksinglepointhandler.cpp
@@ -218,3 +218,5 @@ void QQuickSinglePointHandlerPrivate::reset()
}
QT_END_NAMESPACE
+
+#include "moc_qquicksinglepointhandler_p.cpp"
diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp
index 2284750f15..b722cf7538 100644
--- a/src/quick/handlers/qquicktaphandler.cpp
+++ b/src/quick/handlers/qquicktaphandler.cpp
@@ -431,3 +431,5 @@ void QQuickTapHandler::updateTimeHeld()
from the previous \c tapCount.
*/
QT_END_NAMESPACE
+
+#include "moc_qquicktaphandler_p.cpp"
diff --git a/src/quick/handlers/qquickwheelhandler.cpp b/src/quick/handlers/qquickwheelhandler.cpp
index 16f38af962..7e48d67b8b 100644
--- a/src/quick/handlers/qquickwheelhandler.cpp
+++ b/src/quick/handlers/qquickwheelhandler.cpp
@@ -527,3 +527,5 @@ QMetaProperty &QQuickWheelHandlerPrivate::targetMetaProperty() const
}
QT_END_NAMESPACE
+
+#include "moc_qquickwheelhandler_p.cpp"
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index 14fa07099f..28c62bd4f2 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -3892,16 +3892,16 @@ void QQuickContext2D::bezierCurveTo(qreal cp1x, qreal cp1y,
m_path.cubicTo(QPointF(cp1x, cp1y), QPointF(cp2x, cp2y), pt);
}
-void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radius)
+void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, qreal radius)
{
QPointF p0(m_path.currentPosition());
QPointF p1p0((p0.x() - p1.x()), (p0.y() - p1.y()));
QPointF p1p2((p2.x() - p1.x()), (p2.y() - p1.y()));
- float p1p0_length = std::sqrt(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y());
- float p1p2_length = std::sqrt(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y());
+ qreal p1p0_length = std::hypot(p1p0.x(), p1p0.y());
+ qreal p1p2_length = std::hypot(p1p2.x(), p1p2.y());
- double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length);
+ qreal cos_phi = QPointF::dotProduct(p1p0, p1p2) / (p1p0_length * p1p2_length);
// The points p0, p1, and p2 are on the same straight line (HTML5, 4.8.11.1.8)
// We could have used areCollinear() here, but since we're reusing
@@ -3911,16 +3911,16 @@ void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radiu
return;
}
- float tangent = radius / std::tan(std::acos(cos_phi) / 2);
- float factor_p1p0 = tangent / p1p0_length;
+ qreal tangent = radius / std::tan(std::acos(cos_phi) / 2);
+ qreal factor_p1p0 = tangent / p1p0_length;
QPointF t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y()));
QPointF orth_p1p0(p1p0.y(), -p1p0.x());
- float orth_p1p0_length = std::sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y());
- float factor_ra = radius / orth_p1p0_length;
+ qreal orth_p1p0_length = std::hypot(orth_p1p0.x(), orth_p1p0.y());
+ qreal factor_ra = radius / orth_p1p0_length;
// angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0
- double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length);
+ qreal cos_alpha = QPointF::dotProduct(orth_p1p0, p1p2) / (orth_p1p0_length * p1p2_length);
if (cos_alpha < 0.f)
orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
@@ -3928,20 +3928,15 @@ void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radiu
// calculate angles for addArc
orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
- float sa = std::acos(orth_p1p0.x() / orth_p1p0_length);
- if (orth_p1p0.y() < 0.f)
- sa = 2 * M_PI - sa;
+ qreal sa = std::atan2(orth_p1p0.y(), orth_p1p0.x());
// anticlockwise logic
bool anticlockwise = false;
- float factor_p1p2 = tangent / p1p2_length;
+ qreal factor_p1p2 = tangent / p1p2_length;
QPointF t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y()));
QPointF orth_p1p2((t_p1p2.x() - p.x()), (t_p1p2.y() - p.y()));
- float orth_p1p2_length = std::sqrt(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y());
- float ea = std::acos(orth_p1p2.x() / orth_p1p2_length);
- if (orth_p1p2.y() < 0)
- ea = 2 * M_PI - ea;
+ qreal ea = std::atan2(orth_p1p2.y(), orth_p1p2.x());
if ((sa > ea) && ((sa - ea) < M_PI))
anticlockwise = true;
if ((sa < ea) && ((ea - sa) > M_PI))
diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h
index b5626dec0c..a00689f694 100644
--- a/src/quick/items/context2d/qquickcontext2d_p.h
+++ b/src/quick/items/context2d/qquickcontext2d_p.h
@@ -241,7 +241,7 @@ public:
void arc(qreal x, qreal y, qreal radius,
qreal startAngle, qreal endAngle,
bool anticlockwise);
- void addArcTo(const QPointF& p1, const QPointF& p2, float radius);
+ void addArcTo(const QPointF& p1, const QPointF& p2, qreal radius);
bool isPointInPath(qreal x, qreal y) const;
diff --git a/src/quick/items/qquickaccessibleattached.cpp b/src/quick/items/qquickaccessibleattached.cpp
index 67d17c98e5..70dcaa2acf 100644
--- a/src/quick/items/qquickaccessibleattached.cpp
+++ b/src/quick/items/qquickaccessibleattached.cpp
@@ -406,9 +406,10 @@ void QQuickAccessibleAttached::setRole(QAccessible::Role role)
m_state.focusable = true;
break;
case QAccessible::StaticText:
- if (!m_stateExplicitlySet.readOnly) {
+ if (!m_stateExplicitlySet.readOnly)
m_state.readOnly = true;
- }
+ if (!m_stateExplicitlySet.focusable)
+ m_state.focusable = true;
break;
default:
break;
diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp
index f239f24367..8818bc5608 100644
--- a/src/quick/items/qquickanimatedsprite.cpp
+++ b/src/quick/items/qquickanimatedsprite.cpp
@@ -894,7 +894,7 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGSpriteNode *node)
maybeUpdate();
}
- qreal frameCount = d->m_spriteEngine->spriteFrames();
+ int frameCount = d->m_spriteEngine->spriteFrames();
bool reverse = d->m_spriteEngine->sprite()->reverse();
if (reverse)
frameAt = (frameCount - 1) - frameAt;
@@ -931,15 +931,15 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGSpriteNode *node)
x2 = x1 - w;
y2 = y1;
} else {
- x2 = 1.0 - w;
+ x2 = d->m_sheetSize.width() - w;
y2 = y1 - h;
- if (y2 < 0.0) {
+ if (y2 < 0) {
//the last row may not fill the entire width
int maxRowFrames = d->m_sheetSize.width() / d->m_spriteEngine->spriteWidth();
if (d->m_spriteEngine->maxFrames() % maxRowFrames)
x2 = ((d->m_spriteEngine->maxFrames() % maxRowFrames) - 1) * w;
- y2 = 1.0 - h;
+ y2 = d->m_sheetSize.height() - h;
}
}
} else {
@@ -947,10 +947,10 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGSpriteNode *node)
x2 = x1 + w;
y2 = y1;
} else {
- x2 = 0.0;
+ x2 = 0;
y2 = y1 + h;
- if (y2 >= 1.0)
- y2 = 0.0;
+ if (y2 >= d->m_sheetSize.height())
+ y2 = 0;
}
}
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index 7e673b3fe4..ac962f6f61 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -712,6 +712,8 @@ QQuickPointerDevice *QQuickPointerDevice::tabletDevice(const QTabletEvent *event
switch (event->pointerType()) {
case QTabletEvent::Pen:
ptype = Pen;
+ if (type == QQuickPointerDevice::UnknownDevice)
+ type = QQuickPointerDevice::Stylus;
break;
case QTabletEvent::Eraser:
ptype = Eraser;
@@ -2272,3 +2274,5 @@ Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickEventPoint *eve
#endif
QT_END_NAMESPACE
+
+#include "moc_qquickevents_p_p.cpp"
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index e12e85db64..2634b68248 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -62,6 +62,8 @@
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcHandlerParent)
+Q_LOGGING_CATEGORY(lcVel, "qt.quick.flickable.velocity")
+Q_LOGGING_CATEGORY(lcWheel, "qt.quick.flickable.wheel")
// FlickThreshold determines how far the "mouse" must have moved
// before we perform a flick.
@@ -263,7 +265,8 @@ QQuickFlickablePrivate::QQuickFlickablePrivate()
, deceleration(QML_FLICK_DEFAULTDECELERATION)
, maxVelocity(QML_FLICK_DEFAULTMAXVELOCITY), reportedVelocitySmoothing(100)
, delayedPressEvent(nullptr), pressDelay(0), fixupDuration(400)
- , flickBoost(1.0), fixupMode(Normal), vTime(0), visibleArea(nullptr)
+ , flickBoost(1.0), initialWheelFlickDistance(qApp->styleHints()->wheelScrollLines() * 24)
+ , fixupMode(Normal), vTime(0), visibleArea(nullptr)
, flickableDirection(QQuickFlickable::AutoFlickDirection)
, boundsBehavior(QQuickFlickable::DragAndOvershootBounds)
, boundsMovement(QQuickFlickable::FollowBoundsBehavior)
@@ -323,7 +326,7 @@ void QQuickFlickablePrivate::AxisData::updateVelocity()
}
}
-void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &)
+void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &oldGeom)
{
Q_Q(QQuickFlickable);
if (item == contentItem) {
@@ -332,8 +335,14 @@ void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometr
orient |= Qt::Horizontal;
if (change.yChange())
orient |= Qt::Vertical;
- if (orient)
+ if (orient) {
q->viewportMoved(orient);
+ const QPointF deltaMoved = item->position() - oldGeom.topLeft();
+ if (hData.contentPositionChangedExternallyDuringDrag)
+ hData.pressPos += deltaMoved.x();
+ if (vData.contentPositionChangedExternallyDuringDrag)
+ vData.pressPos += deltaMoved.y();
+ }
if (orient & Qt::Horizontal)
emit q->contentXChanged();
if (orient & Qt::Vertical)
@@ -531,10 +540,14 @@ void QQuickFlickablePrivate::updateBeginningEnd()
if (atBeginning != vData.atBeginning) {
vData.atBeginning = atBeginning;
atYBeginningChange = true;
+ if (!vData.moving && atBeginning)
+ vData.smoothVelocity.setValue(0);
}
if (atEnd != vData.atEnd) {
vData.atEnd = atEnd;
atYEndChange = true;
+ if (!vData.moving && atEnd)
+ vData.smoothVelocity.setValue(0);
}
// Horizontal
@@ -547,10 +560,14 @@ void QQuickFlickablePrivate::updateBeginningEnd()
if (atBeginning != hData.atBeginning) {
hData.atBeginning = atBeginning;
atXBeginningChange = true;
+ if (!hData.moving && atBeginning)
+ hData.smoothVelocity.setValue(0);
}
if (atEnd != hData.atEnd) {
hData.atEnd = atEnd;
atXEndChange = true;
+ if (!hData.moving && atEnd)
+ hData.smoothVelocity.setValue(0);
}
if (vData.extentsChanged) {
@@ -785,8 +802,11 @@ void QQuickFlickable::setContentX(qreal pos)
d->hData.vTime = d->timeline.time();
if (isMoving() || isFlicking())
movementEnding(true, false);
- if (!qFuzzyCompare(-pos, d->hData.move.value()))
+ if (!qFuzzyCompare(-pos, d->hData.move.value())) {
+ d->hData.contentPositionChangedExternallyDuringDrag = d->hData.dragging;
d->hData.move.setValue(-pos);
+ d->hData.contentPositionChangedExternallyDuringDrag = false;
+ }
}
qreal QQuickFlickable::contentY() const
@@ -803,8 +823,11 @@ void QQuickFlickable::setContentY(qreal pos)
d->vData.vTime = d->timeline.time();
if (isMoving() || isFlicking())
movementEnding(false, true);
- if (!qFuzzyCompare(-pos, d->vData.move.value()))
+ if (!qFuzzyCompare(-pos, d->vData.move.value())) {
+ d->vData.contentPositionChangedExternallyDuringDrag = d->vData.dragging;
d->vData.move.setValue(-pos);
+ d->vData.contentPositionChangedExternallyDuringDrag = false;
+ }
}
/*!
@@ -1489,6 +1512,7 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
d->hData.velocity = 0;
d->timer.start();
d->maybeBeginDrag(currentTimestamp, event->position());
+ d->lastPosTime = -1;
break;
case Qt::NoScrollPhase: // default phase with an ordinary wheel mouse
case Qt::ScrollUpdate:
@@ -1515,20 +1539,34 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
return;
}
+ qreal elapsed = qreal(currentTimestamp - d->lastPosTime) / qreal(1000);
+ if (elapsed <= 0) {
+ d->lastPosTime = currentTimestamp;
+ qCDebug(lcWheel) << "insufficient elapsed time: can't calculate velocity" << elapsed;
+ return;
+ }
+
if (event->source() == Qt::MouseEventNotSynthesized || event->pixelDelta().isNull()) {
- // physical mouse wheel, so use angleDelta
+ // no pixel delta (physical mouse wheel, or "dumb" touchpad), so use angleDelta
int xDelta = event->angleDelta().x();
int yDelta = event->angleDelta().y();
+ // For a single "clicky" wheel event (angleDelta +/- 120),
+ // we want flick() to end up moving a distance proportional to QStyleHints::wheelScrollLines().
+ // The decel algo from there is
+ // qreal dist = v2 / (accel * 2.0);
+ // i.e. initialWheelFlickDistance = (120 / dt)^2 / (deceleration * 2)
+ // now solve for dt:
+ // dt = 120 / sqrt(deceleration * 2 * initialWheelFlickDistance)
+ if (!isMoving())
+ elapsed = 120 / qSqrt(d->deceleration * 2 * d->initialWheelFlickDistance);
if (yflick() && yDelta != 0) {
- bool valid = false;
- if (yDelta > 0 && contentY() > -minYExtent()) {
- d->vData.velocity = qMax(yDelta*2 - d->vData.smoothVelocity.value(), qreal(d->maxVelocity/4));
- valid = true;
- } else if (yDelta < 0 && contentY() < -maxYExtent()) {
- d->vData.velocity = qMin(yDelta*2 - d->vData.smoothVelocity.value(), qreal(-d->maxVelocity/4));
- valid = true;
- }
- if (valid) {
+ qreal instVelocity = yDelta / elapsed;
+ // if the direction has changed, start over with filtering, to allow instant movement in the opposite direction
+ if ((instVelocity < 0 && d->vData.velocity > 0) || (instVelocity > 0 && d->vData.velocity < 0))
+ d->vData.velocityBuffer.clear();
+ d->vData.addVelocitySample(instVelocity, d->maxVelocity);
+ d->vData.updateVelocity();
+ if ((yDelta > 0 && contentY() > -minYExtent()) || (yDelta < 0 && contentY() < -maxYExtent())) {
d->flickY(d->vData.velocity);
d->flickingStarted(false, true);
if (d->vData.flicking) {
@@ -1539,15 +1577,13 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
}
}
if (xflick() && xDelta != 0) {
- bool valid = false;
- if (xDelta > 0 && contentX() > -minXExtent()) {
- d->hData.velocity = qMax(xDelta*2 - d->hData.smoothVelocity.value(), qreal(d->maxVelocity/4));
- valid = true;
- } else if (xDelta < 0 && contentX() < -maxXExtent()) {
- d->hData.velocity = qMin(xDelta*2 - d->hData.smoothVelocity.value(), qreal(-d->maxVelocity/4));
- valid = true;
- }
- if (valid) {
+ qreal instVelocity = xDelta / elapsed;
+ // if the direction has changed, start over with filtering, to allow instant movement in the opposite direction
+ if ((instVelocity < 0 && d->hData.velocity > 0) || (instVelocity > 0 && d->hData.velocity < 0))
+ d->hData.velocityBuffer.clear();
+ d->hData.addVelocitySample(instVelocity, d->maxVelocity);
+ d->hData.updateVelocity();
+ if ((xDelta > 0 && contentX() > -minXExtent()) || (xDelta < 0 && contentX() < -maxXExtent())) {
d->flickX(d->hData.velocity);
d->flickingStarted(true, false);
if (d->hData.flicking) {
@@ -1562,18 +1598,13 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
int xDelta = event->pixelDelta().x();
int yDelta = event->pixelDelta().y();
- qreal elapsed = qreal(currentTimestamp - d->lastPosTime) / 1000.;
- if (elapsed <= 0) {
- d->lastPosTime = currentTimestamp;
- return;
- }
QVector2D velocity(xDelta / elapsed, yDelta / elapsed);
- d->lastPosTime = currentTimestamp;
d->accumulatedWheelPixelDelta += QVector2D(event->pixelDelta());
d->drag(currentTimestamp, event->type(), event->position(), d->accumulatedWheelPixelDelta,
true, !d->scrollingPhase, true, velocity);
event->accept();
}
+ d->lastPosTime = currentTimestamp;
if (!event->isAccepted())
QQuickItem::wheelEvent(event);
@@ -1744,6 +1775,10 @@ void QQuickFlickable::componentComplete()
setContentX(-minXExtent());
if (!d->vData.explicitValue && d->vData.startMargin != 0.)
setContentY(-minYExtent());
+ if (lcWheel().isDebugEnabled() || lcVel().isDebugEnabled()) {
+ d->timeline.setObjectName(QLatin1String("timeline for Flickable ") + objectName());
+ d->velocityTimeline.setObjectName(QLatin1String("velocity timeline for Flickable ") + objectName());
+ }
}
void QQuickFlickable::viewportMoved(Qt::Orientations orient)
@@ -2504,9 +2539,23 @@ void QQuickFlickable::setMaximumFlickVelocity(qreal v)
/*!
\qmlproperty real QtQuick::Flickable::flickDeceleration
- This property holds the rate at which a flick will decelerate.
-
- The default value is platform dependent.
+ This property holds the rate at which a flick will decelerate:
+ the higher the number, the faster it slows down when the user stops
+ flicking via touch, touchpad or mouse wheel. For example 0.0001 is nearly
+ "frictionless", and 10000 feels quite "sticky".
+
+ The default value is platform dependent. Values of zero or less are not allowed.
+
+ \note For touchpad flicking, some platforms drive Flickable directly by
+ sending QWheelEvents with QWheelEvent::phase() being \c Qt::ScrollMomentum,
+ after the user has released all fingers from the touchpad. In that case,
+ the operating system is controlling the deceleration, and this property has
+ no effect.
+
+ \note For mouse wheel scrolling, and for gesture scrolling on touchpads
+ that do not have a momentum phase, extremely large values of
+ flickDeceleration can make Flickable very resistant to scrolling,
+ especially if \l maximumFlickVelocity is too small.
*/
qreal QQuickFlickable::flickDeceleration() const
{
@@ -2519,7 +2568,7 @@ void QQuickFlickable::setFlickDeceleration(qreal deceleration)
Q_D(QQuickFlickable);
if (deceleration == d->deceleration)
return;
- d->deceleration = deceleration;
+ d->deceleration = qMax(0.001, deceleration);
emit flickDecelerationChanged();
}
@@ -2729,6 +2778,12 @@ void QQuickFlickable::movementStarting()
if (!wasMoving && (d->hData.moving || d->vData.moving)) {
emit movingChanged();
emit movementStarted();
+#if QT_CONFIG(accessibility)
+ if (QAccessible::isActive()) {
+ QAccessibleEvent ev(this, QAccessible::ScrollingStart);
+ QAccessible::updateAccessibility(&ev);
+ }
+#endif
}
}
@@ -2773,6 +2828,12 @@ void QQuickFlickable::movementEnding(bool hMovementEnding, bool vMovementEnding)
if (wasMoving && !isMoving()) {
emit movingChanged();
emit movementEnded();
+#if QT_CONFIG(accessibility)
+ if (QAccessible::isActive()) {
+ QAccessibleEvent ev(this, QAccessible::ScrollingEnd);
+ QAccessible::updateAccessibility(&ev);
+ }
+#endif
}
if (hMovementEnding) {
@@ -2900,4 +2961,6 @@ void QQuickFlickable::setBoundsMovement(BoundsMovement movement)
QT_END_NAMESPACE
+#include "moc_qquickflickable_p_p.cpp"
+
#include "moc_qquickflickable_p.cpp"
diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h
index 414c9c33d6..aef15e150a 100644
--- a/src/quick/items/qquickflickable_p_p.h
+++ b/src/quick/items/qquickflickable_p_p.h
@@ -109,6 +109,7 @@ public:
, fixingUp(false), inOvershoot(false), inRebound(false), moving(false), flicking(false)
, dragging(false), extentsChanged(false)
, explicitValue(false), minExtentDirty(true), maxExtentDirty(true)
+ , contentPositionChangedExternallyDuringDrag(false)
, unused(0)
{}
@@ -119,6 +120,7 @@ public:
dragStartOffset = 0;
fixingUp = false;
inOvershoot = false;
+ contentPositionChangedExternallyDuringDrag = false;
}
void markExtentsDirty() {
@@ -169,7 +171,8 @@ public:
bool explicitValue : 1;
mutable bool minExtentDirty : 1;
mutable bool maxExtentDirty : 1;
- uint unused : 19;
+ bool contentPositionChangedExternallyDuringDrag : 1;
+ uint unused : 18;
};
bool flickX(qreal velocity);
@@ -241,6 +244,7 @@ public:
int pressDelay;
int fixupDuration;
qreal flickBoost;
+ qreal initialWheelFlickDistance;
enum FixupMode { Normal, Immediate, ExtentChanged };
FixupMode fixupMode;
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp
index 7ca5b0c34c..0a1f7681d6 100644
--- a/src/quick/items/qquickgridview.cpp
+++ b/src/quick/items/qquickgridview.cpp
@@ -1653,6 +1653,7 @@ void QQuickGridView::setCellWidth(qreal cellWidth)
d->updateViewport();
emit cellWidthChanged();
d->forceLayoutPolish();
+ QQuickFlickable::setContentX(d->contentXForPosition(d->position()));
}
}
@@ -1670,6 +1671,7 @@ void QQuickGridView::setCellHeight(qreal cellHeight)
d->updateViewport();
emit cellHeightChanged();
d->forceLayoutPolish();
+ QQuickFlickable::setContentY(d->contentYForPosition(d->position()));
}
}
/*!
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index 04c5da6167..bf6e17a5d7 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -945,3 +945,7 @@ void QQuickImage::setMipmap(bool use)
*/
QT_END_NAMESPACE
+
+#include "moc_qquickimage_p_p.cpp"
+
+#include "moc_qquickimage_p.cpp"
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 75f1457816..33da9762d3 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -4543,10 +4543,10 @@ static bool unwrapMapFromToFromItemArgs(QQmlV4Function *args, const QQuickItem *
}
/*!
- \qmlmethod object QtQuick::Item::mapFromItem(Item item, real x, real y)
- \qmlmethod object QtQuick::Item::mapFromItem(Item item, point p)
- \qmlmethod object QtQuick::Item::mapFromItem(Item item, real x, real y, real width, real height)
- \qmlmethod object QtQuick::Item::mapFromItem(Item item, rect r)
+ \qmlmethod point QtQuick::Item::mapFromItem(Item item, real x, real y)
+ \qmlmethod point QtQuick::Item::mapFromItem(Item item, point p)
+ \qmlmethod rect QtQuick::Item::mapFromItem(Item item, real x, real y, real width, real height)
+ \qmlmethod rect QtQuick::Item::mapFromItem(Item item, rect r)
Maps the point (\a x, \a y) or rect (\a x, \a y, \a width, \a height), which is in \a
item's coordinate system, to this item's coordinate system, and returns a \l point or \l rect
@@ -4598,10 +4598,10 @@ QTransform QQuickItem::itemTransform(QQuickItem *other, bool *ok) const
}
/*!
- \qmlmethod object QtQuick::Item::mapToItem(Item item, real x, real y)
- \qmlmethod object QtQuick::Item::mapToItem(Item item, point p)
- \qmlmethod object QtQuick::Item::mapToItem(Item item, real x, real y, real width, real height)
- \qmlmethod object QtQuick::Item::mapToItem(Item item, rect r)
+ \qmlmethod point QtQuick::Item::mapToItem(Item item, real x, real y)
+ \qmlmethod point QtQuick::Item::mapToItem(Item item, point p)
+ \qmlmethod rect QtQuick::Item::mapToItem(Item item, real x, real y, real width, real height)
+ \qmlmethod rect QtQuick::Item::mapToItem(Item item, rect r)
Maps the point (\a x, \a y) or rect (\a x, \a y, \a width, \a height), which is in this
item's coordinate system, to \a item's coordinate system, and returns a \l point or \l rect
@@ -4683,7 +4683,7 @@ static bool unwrapMapFromToFromGlobalArgs(QQmlV4Function *args, const QQuickItem
/*!
\since 5.7
- \qmlmethod object QtQuick::Item::mapFromGlobal(real x, real y)
+ \qmlmethod point QtQuick::Item::mapFromGlobal(real x, real y)
Maps the point (\a x, \a y), which is in the global coordinate system, to the
item's coordinate system, and returns a \l point matching the mapped coordinate.
@@ -4710,7 +4710,7 @@ void QQuickItem::mapFromGlobal(QQmlV4Function *args) const
/*!
\since 5.7
- \qmlmethod object QtQuick::Item::mapToGlobal(real x, real y)
+ \qmlmethod point QtQuick::Item::mapToGlobal(real x, real y)
Maps the point (\a x, \a y), which is in this item's coordinate system, to the
global coordinate system, and returns a \l point matching the mapped coordinate.
@@ -7887,10 +7887,26 @@ bool QQuickItem::contains(const QPointF &point) const
\e{item}'s contains method would then return \c true only if
\e{anotherItem}'s contains() implementation returns \c true.
- A \l Shape can be used in this way, to make an item react to
- \l {QPointerEvent}{pointer events} only within a non-rectangular region,
- as illustrated in the \l {Qt Quick Examples - Shapes}{Shapes example}
- (see \c tapableTriangle.qml).
+ A \l Shape can be used as a mask, to make an item react to
+ \l {QPointerEvent}{pointer events} only within a non-rectangular region:
+
+ \table
+ \row
+ \li \image containmentMask-shape.gif
+ \li \snippet qml/item/containmentMask-shape.qml 0
+ \endtable
+
+ It is also possible to define the contains method in QML. For example,
+ to create a circular item that only responds to events within its
+ actual bounds:
+
+ \table
+ \row
+ \li \image containmentMask-circle.gif
+ \li \snippet qml/item/containmentMask-circle-js.qml 0
+ \endtable
+
+ \sa {Qt Quick Examples - Shapes}
*/
/*!
\property QQuickItem::containmentMask
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 125518e51b..f14b29b1b8 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -128,6 +128,8 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcTransient)
QT_END_NAMESPACE
+#include "moc_qquickitemsmodule_p.cpp"
+
static QQmlPrivate::AutoParentResult qquickitem_autoParent(QObject *obj, QObject *parent)
{
// When setting a parent (especially during dynamic object creation) in QML,
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 13e7b87049..29afaae93b 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -290,8 +290,6 @@ void QQuickItemView::setDelegate(QQmlComponent *delegate)
if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model)) {
int oldCount = dataModel->count();
dataModel->setDelegate(delegate);
- if (isComponentComplete())
- d->applyDelegateChange();
if (oldCount != dataModel->count())
emit countChanged();
}
@@ -1785,7 +1783,7 @@ void QQuickItemViewPrivate::refill(qreal from, qreal to)
do {
bufferPause.stop();
- if (currentChanges.hasPendingChanges() || bufferedChanges.hasPendingChanges()) {
+ if (currentChanges.hasPendingChanges() || bufferedChanges.hasPendingChanges() || currentChanges.active) {
currentChanges.reset();
bufferedChanges.reset();
releaseVisibleItems(reusableFlag);
@@ -2402,8 +2400,6 @@ void QQuickItemView::createdItem(int index, QObject* object)
d->repositionPackageItemAt(item, index);
else if (index == d->currentIndex)
d->updateCurrent(index);
- } else if (index == d->currentIndex) {
- d->updateCurrent(index);
}
}
diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp
index b7649c9952..78b379d5a2 100644
--- a/src/quick/items/qquickitemviewtransition.cpp
+++ b/src/quick/items/qquickitemviewtransition.cpp
@@ -125,6 +125,8 @@ void QQuickItemViewTransitionJob::startTransition(QQuickItemViewTransitionableIt
actions << QQuickStateAction(item->item, QLatin1String("x"), QVariant(to.x()));
actions << QQuickStateAction(item->item, QLatin1String("y"), QVariant(to.y()));
+ actions[0].fromValue = item->itemX();
+ actions[1].fromValue = item->itemY();
m_transitioner->runningJobs << this;
QQuickTransitionManager::transition(actions, trans, item->item);
}
@@ -555,9 +557,15 @@ void QQuickItemViewTransitionableItem::stopTransition()
QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent)
- : QObject(parent), m_item(nullptr), m_index(-1)
+ : QObject(parent), m_index(-1)
{
}
+
+QQuickItem *QQuickViewTransitionAttached::item() const
+{
+ return m_item.data();
+}
+
/*!
\qmltype ViewTransition
\instantiates QQuickViewTransitionAttached
diff --git a/src/quick/items/qquickitemviewtransition_p.h b/src/quick/items/qquickitemviewtransition_p.h
index 5f4e74171e..bedef93d0b 100644
--- a/src/quick/items/qquickitemviewtransition_p.h
+++ b/src/quick/items/qquickitemviewtransition_p.h
@@ -202,7 +202,7 @@ public:
QQuickViewTransitionAttached(QObject *parent);
int index() const { return m_index; }
- QQuickItem *item() const { return m_item; }
+ QQuickItem *item() const;
QPointF destination() const { return m_destination; }
QList<int> targetIndexes() const { return m_targetIndexes; }
@@ -224,7 +224,7 @@ private:
QList<int> m_targetIndexes;
QList<QObject *> m_targetItems;
- QQuickItem *m_item;
+ QPointer<QQuickItem> m_item;
int m_index;
};
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index 7fbe66fdda..0a5514d5f9 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -439,9 +439,8 @@ void QQuickLoader::loadFromSource()
}
if (isComponentComplete()) {
- QQmlComponent::CompilationMode mode = d->asynchronous ? QQmlComponent::Asynchronous : QQmlComponent::PreferSynchronous;
if (!d->component)
- d->component.setObject(new QQmlComponent(qmlEngine(this), d->source, mode, this), this);
+ d->createComponent();
d->load();
}
}
@@ -806,11 +805,8 @@ void QQuickLoader::componentComplete()
Q_D(QQuickLoader);
QQuickItem::componentComplete();
if (active()) {
- if (d->loadingFromSource) {
- QQmlComponent::CompilationMode mode = d->asynchronous ? QQmlComponent::Asynchronous : QQmlComponent::PreferSynchronous;
- if (!d->component)
- d->component.setObject(new QQmlComponent(qmlEngine(this), d->source, mode, this), this);
- }
+ if (d->loadingFromSource && !d->component)
+ d->createComponent();
d->load();
}
}
@@ -946,7 +942,7 @@ void QQuickLoaderPrivate::_q_updateSize(bool loaderGeometryChanged)
}
/*!
- \qmlproperty object QtQuick::Loader::item
+ \qmlproperty QtObject QtQuick::Loader::item
This property holds the top-level object that is currently loaded.
Since \c {QtQuick 2.0}, Loader can load any object type.
@@ -1044,6 +1040,22 @@ void QQuickLoaderPrivate::updateStatus()
}
}
+void QQuickLoaderPrivate::createComponent()
+{
+ Q_Q(QQuickLoader);
+ const QQmlComponent::CompilationMode mode = asynchronous
+ ? QQmlComponent::Asynchronous
+ : QQmlComponent::PreferSynchronous;
+ if (QQmlContext *context = qmlContext(q)) {
+ if (QQmlEngine *engine = context->engine()) {
+ component.setObject(new QQmlComponent(engine, source, mode, q), q);
+ return;
+ }
+ }
+
+ qmlWarning(q) << "createComponent: Cannot find a QML engine.";
+}
+
#include <moc_qquickloader_p.cpp>
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickloader_p_p.h b/src/quick/items/qquickloader_p_p.h
index 39d50280c5..b178803c7d 100644
--- a/src/quick/items/qquickloader_p_p.h
+++ b/src/quick/items/qquickloader_p_p.h
@@ -98,6 +98,7 @@ public:
QV4::ReturnedValue extractInitialPropertyValues(QQmlV4Function *args, QObject *loader, bool *error);
QQuickLoader::Status computeStatus() const;
void updateStatus();
+ void createComponent();
qreal getImplicitWidth() const override;
qreal getImplicitHeight() const override;
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index 982d089b5f..3e2e4fc1cf 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -806,7 +806,8 @@ void QQuickMouseArea::mouseReleaseEvent(QMouseEvent *event)
QQuickWindow *w = window();
if (w && w->mouseGrabberItem() == this)
ungrabMouse();
- setKeepMouseGrab(false);
+ if (!d->preventStealing)
+ setKeepMouseGrab(false);
}
}
d->doubleClick = false;
@@ -825,7 +826,8 @@ void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event)
emit this->doubleClicked(&me);
if (!me.isAccepted())
d->propagate(&me, QQuickMouseAreaPrivate::DoubleClick);
- d->doubleClick = d->isDoubleClickConnected() || me.isAccepted();
+ if (d->pressed)
+ d->doubleClick = d->isDoubleClickConnected() || me.isAccepted();
}
QQuickItem::mouseDoubleClickEvent(event);
}
diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp
index 383718c979..4d420969cf 100644
--- a/src/quick/items/qquickmultipointtoucharea.cpp
+++ b/src/quick/items/qquickmultipointtoucharea.cpp
@@ -569,7 +569,7 @@ void QQuickMultiPointTouchArea::grabGesture()
setKeepTouchGrab(true);
}
-void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
+void QQuickMultiPointTouchArea::updateTouchData(QEvent *event, RemapEventPoints remap)
{
bool ended = false;
bool moved = false;
@@ -578,12 +578,14 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
clearTouchLists();
QList<QTouchEvent::TouchPoint> touchPoints;
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window());
+ bool touchPointsFromEvent = false;
switch (event->type()) {
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
touchPoints = static_cast<QTouchEvent*>(event)->touchPoints();
+ touchPointsFromEvent = true;
break;
case QEvent::MouseButtonPress:
_mouseQpaTouchPoint = QTouchEvent::TouchPoint(windowPriv->touchMouseId);
@@ -614,6 +616,8 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
qWarning("updateTouchData: unhandled event type %d", event->type());
break;
}
+ if (!touchPointsFromEvent)
+ remap = RemapEventPoints::No;
int numTouchPoints = touchPoints.count();
//always remove released touches, and make sure we handle all releases before adds.
@@ -624,7 +628,7 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints.value(id));
if (!dtp)
continue;
- updateTouchPoint(dtp, &p);
+ updateTouchPoint(dtp, &p, RemapEventPoints::No);
dtp->setPressed(false);
_releasedTouchPoints.append(dtp);
_touchPoints.remove(id);
@@ -639,19 +643,19 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
//handled above
} else if (!_touchPoints.contains(id)) { //could be pressed, moved, or stationary
// (we may have just obtained enough points to start tracking them -- in that case moved or stationary count as newly pressed)
- addTouchPoint(&p);
+ addTouchPoint(&p, remap);
started = true;
} else if ((touchPointState & Qt::TouchPointMoved) || p.d->stationaryWithModifiedProperty) {
// React to a stationary point with a property change (velocity, pressure) as if the point moved. (QTBUG-77142)
QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints.value(id));
Q_ASSERT(dtp);
_movedTouchPoints.append(dtp);
- updateTouchPoint(dtp,&p);
+ updateTouchPoint(dtp, &p, remap);
moved = true;
} else {
QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints.value(id));
Q_ASSERT(dtp);
- updateTouchPoint(dtp,&p);
+ updateTouchPoint(dtp, &p, remap);
}
}
@@ -685,7 +689,7 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
emit released(_releasedTouchPoints);
if (moved)
emit updated(_movedTouchPoints);
- if (started)
+ if (started && !_pressedTouchPoints.isEmpty())
emit pressed(_pressedTouchPoints);
if (ended || moved || started) emit touchUpdated(_touchPoints.values());
}
@@ -707,7 +711,7 @@ void QQuickMultiPointTouchArea::clearTouchLists()
_movedTouchPoints.clear();
}
-void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p)
+void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p, RemapEventPoints remap)
{
QQuickTouchPoint *dtp = nullptr;
for (QQuickTouchPoint* tp : qAsConst(_touchPrototypes)) {
@@ -721,7 +725,7 @@ void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p)
if (dtp == nullptr)
dtp = new QQuickTouchPoint(false);
dtp->setPointId(p->id());
- updateTouchPoint(dtp,p);
+ updateTouchPoint(dtp, p, remap);
dtp->setPressed(true);
_touchPoints.insert(p->id(),dtp);
_pressedTouchPoints.append(dtp);
@@ -730,12 +734,15 @@ void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p)
void QQuickMultiPointTouchArea::addTouchPoint(const QMouseEvent *e)
{
QQuickTouchPoint *dtp = nullptr;
- for (QQuickTouchPoint *tp : qAsConst(_touchPrototypes))
+ for (QQuickTouchPoint *tp : qAsConst(_touchPrototypes)) {
if (!tp->inUse()) {
tp->setInUse(true);
dtp = tp;
break;
+ } else if (_mouseTouchPoint == tp) {
+ return; // do not allow more than one touchpoint to react to the mouse (QTBUG-83662)
}
+ }
if (dtp == nullptr)
dtp = new QQuickTouchPoint(false);
@@ -779,12 +786,12 @@ void QQuickMultiPointTouchArea::addTouchPrototype(QQuickTouchPoint *prototype)
_touchPrototypes.insert(id, prototype);
}
-void QQuickMultiPointTouchArea::updateTouchPoint(QQuickTouchPoint *dtp, const QTouchEvent::TouchPoint *p)
+void QQuickMultiPointTouchArea::updateTouchPoint(QQuickTouchPoint *dtp, const QTouchEvent::TouchPoint *p, RemapEventPoints remap)
{
//TODO: if !qmlDefined, could bypass setters.
// also, should only emit signals after all values have been set
dtp->setUniqueId(p->uniqueId());
- dtp->setPosition(p->pos());
+ dtp->setPosition(remap == RemapEventPoints::ToLocal ? mapFromScene(p->scenePos()) : p->pos());
dtp->setEllipseDiameters(p->ellipseDiameters());
dtp->setPressure(p->pressure());
dtp->setRotation(p->rotation());
@@ -972,12 +979,12 @@ bool QQuickMultiPointTouchArea::childMouseEventFilter(QQuickItem *receiver, QEve
}
if (!shouldFilter(event))
return false;
- updateTouchData(event);
+ updateTouchData(event, RemapEventPoints::ToLocal);
return _stealMouse;
case QEvent::TouchEnd: {
if (!shouldFilter(event))
return false;
- updateTouchData(event);
+ updateTouchData(event, RemapEventPoints::ToLocal);
ungrab(true);
}
break;
diff --git a/src/quick/items/qquickmultipointtoucharea_p.h b/src/quick/items/qquickmultipointtoucharea_p.h
index e34a3faad6..85c1e2258e 100644
--- a/src/quick/items/qquickmultipointtoucharea_p.h
+++ b/src/quick/items/qquickmultipointtoucharea_p.h
@@ -267,14 +267,15 @@ protected:
void mouseUngrabEvent() override;
void touchUngrabEvent() override;
+ enum class RemapEventPoints { No, ToLocal };
void addTouchPrototype(QQuickTouchPoint* prototype);
- void addTouchPoint(const QTouchEvent::TouchPoint *p);
+ void addTouchPoint(const QTouchEvent::TouchPoint *p, RemapEventPoints remap);
void addTouchPoint(const QMouseEvent *e);
void clearTouchLists();
- void updateTouchPoint(QQuickTouchPoint*, const QTouchEvent::TouchPoint*);
+ void updateTouchPoint(QQuickTouchPoint*, const QTouchEvent::TouchPoint*, RemapEventPoints remap);
void updateTouchPoint(QQuickTouchPoint *dtp, const QMouseEvent *e);
- void updateTouchData(QEvent*);
+ void updateTouchData(QEvent*, RemapEventPoints remap = RemapEventPoints::No);
bool sendMouseEvent(QMouseEvent *event);
bool shouldFilter(QEvent *event);
diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp
index 1a07eb5923..df6f271b0d 100644
--- a/src/quick/items/qquickpincharea.cpp
+++ b/src/quick/items/qquickpincharea.cpp
@@ -710,6 +710,8 @@ bool QQuickPinchArea::event(QEvent *event)
clearPinch();
break;
case Qt::ZoomNativeGesture: {
+ if (d->pinchRejected)
+ break;
qreal scale = d->pinchLastScale * (1.0 + gesture->value());
QQuickPinchEvent pe(d->pinchStartCenter, scale, d->pinchLastAngle, 0.0);
pe.setStartCenter(d->pinchStartCenter);
@@ -727,7 +729,10 @@ bool QQuickPinchArea::event(QEvent *event)
else
emit pinchStarted(&pe);
d->inPinch = true;
- updatePinchTarget();
+ if (pe.accepted())
+ updatePinchTarget();
+ else
+ d->pinchRejected = true;
} break;
case Qt::SmartZoomNativeGesture: {
if (gesture->value() > 0.0 && d->pinch && d->pinch->target()) {
@@ -751,6 +756,8 @@ bool QQuickPinchArea::event(QEvent *event)
emit smartZoom(&pe);
} break;
case Qt::RotateNativeGesture: {
+ if (d->pinchRejected)
+ break;
qreal angle = d->pinchLastAngle + gesture->value();
QQuickPinchEvent pe(d->pinchStartCenter, d->pinchLastScale, angle, 0.0);
pe.setStartCenter(d->pinchStartCenter);
@@ -769,7 +776,10 @@ bool QQuickPinchArea::event(QEvent *event)
emit pinchStarted(&pe);
d->inPinch = true;
d->pinchRotation = angle;
- updatePinchTarget();
+ if (pe.accepted())
+ updatePinchTarget();
+ else
+ d->pinchRejected = true;
} break;
default:
return QQuickItem::event(event);
diff --git a/src/quick/items/qquickscalegrid.cpp b/src/quick/items/qquickscalegrid.cpp
index 23f179be1d..82875c9e52 100644
--- a/src/quick/items/qquickscalegrid.cpp
+++ b/src/quick/items/qquickscalegrid.cpp
@@ -217,3 +217,5 @@ QString QQuickGridScaledImage::pixmapUrl() const
}
QT_END_NAMESPACE
+
+#include "moc_qquickscalegrid_p_p.cpp"
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp
index 4f61d61309..b298ed74da 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -344,7 +344,6 @@ void QQuickShaderEffectSource::setSourceItem(QQuickItem *item)
d->refFromEffectItem(m_hideSource);
d->addItemChangeListener(this, QQuickItemPrivate::Geometry);
connect(m_sourceItem, SIGNAL(destroyed(QObject*)), this, SLOT(sourceItemDestroyed(QObject*)));
- connect(m_sourceItem, SIGNAL(parentChanged(QQuickItem*)), this, SLOT(sourceItemParentChanged(QQuickItem*)));
} else {
qWarning("ShaderEffectSource: sourceItem and ShaderEffectSource must both be children of the same window.");
m_sourceItem = nullptr;
@@ -364,13 +363,6 @@ void QQuickShaderEffectSource::sourceItemDestroyed(QObject *item)
}
-void QQuickShaderEffectSource::sourceItemParentChanged(QQuickItem *parent)
-{
- if (!parent && m_texture)
- m_texture->setItem(0);
-}
-
-
/*!
\qmlproperty rect QtQuick::ShaderEffectSource::sourceRect
diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h
index 4deb6c70a3..c0a1ccab78 100644
--- a/src/quick/items/qquickshadereffectsource_p.h
+++ b/src/quick/items/qquickshadereffectsource_p.h
@@ -173,7 +173,6 @@ Q_SIGNALS:
private Q_SLOTS:
void sourceItemDestroyed(QObject *item);
void invalidateSceneGraph();
- void sourceItemParentChanged(QQuickItem *parent);
protected:
void releaseResources() override;
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index 5feec60874..3c10a65450 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -3096,3 +3096,5 @@ QQuickTableSectionSizeProviderPrivate::~QQuickTableSectionSizeProviderPrivate()
#include "moc_qquicktableview_p.cpp"
QT_END_NAMESPACE
+
+#include "moc_qquicktableview_p_p.cpp"
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 6230186933..d8fd2017e3 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -965,7 +965,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
const qreal availWidth = availableWidth();
const qreal availHeight = availableHeight();
- lineWidth = q->widthValid() && availWidth > 0 ? availWidth : naturalWidth;
+ lineWidth = q->widthValid() && q->width() > 0 ? availWidth : naturalWidth;
maxHeight = q->heightValid() ? availHeight : FLT_MAX;
// If the width of the item has changed and it's possible the result of wrapping,
@@ -2168,7 +2168,7 @@ void QQuickText::resetMaximumLineCount()
<img src="" align="top,middle,bottom" width="" height=""> - inline images
<ol type="">, <ul type=""> and <li> - ordered and unordered lists
<pre></pre> - preformatted
- &gt; &lt; &amp;
+ &gt; &lt; &amp; &quot; &nbsp; &apos;
\endcode
\c Text.StyledText parser is strict, requiring tags to be correctly nested.
@@ -2409,21 +2409,23 @@ void QQuickText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo
goto geomChangeDone;
if (!(widthChanged || widthMaximum) && !d->isLineLaidOutConnected()) { // only height has changed
- if (newGeometry.height() > oldGeometry.height()) {
- if (!d->heightExceeded && !qFuzzyIsNull(oldGeometry.height())) {
- // Height is adequate and growing, and it wasn't 0 previously.
- goto geomChangeDone;
- }
- if (d->lineCount == d->maximumLineCount()) // Reached maximum line and height is growing.
- goto geomChangeDone;
- } else if (newGeometry.height() < oldGeometry.height()) {
- if (d->lineCount < 2 && !verticalScale && newGeometry.height() > 0) // A single line won't be truncated until the text is 0 height.
- goto geomChangeDone;
-
- if (!verticalScale // no scaling, no eliding, and either unwrapped, or no maximum line count.
- && d->elideMode != QQuickText::ElideRight
- && !(d->maximumLineCountValid && d->widthExceeded)) {
- goto geomChangeDone;
+ if (!verticalPositionChanged) {
+ if (newGeometry.height() > oldGeometry.height()) {
+ if (!d->heightExceeded && !qFuzzyIsNull(oldGeometry.height())) {
+ // Height is adequate and growing, and it wasn't 0 previously.
+ goto geomChangeDone;
+ }
+ if (d->lineCount == d->maximumLineCount()) // Reached maximum line and height is growing.
+ goto geomChangeDone;
+ } else if (newGeometry.height() < oldGeometry.height()) {
+ if (d->lineCount < 2 && !verticalScale && newGeometry.height() > 0) // A single line won't be truncated until the text is 0 height.
+ goto geomChangeDone;
+
+ if (!verticalScale // no scaling, no eliding, and either unwrapped, or no maximum line count.
+ && d->elideMode != QQuickText::ElideRight
+ && !(d->maximumLineCountValid && d->widthExceeded)) {
+ goto geomChangeDone;
+ }
}
}
} else if (!heightChanged && widthMaximum) {
diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h
index 0fffc1fb9a..698f9649dd 100644
--- a/src/quick/items/qquicktext_p.h
+++ b/src/quick/items/qquicktext_p.h
@@ -326,6 +326,8 @@ private:
Q_DECLARE_PRIVATE(QQuickText)
};
+Q_DECLARE_MIXED_ENUM_OPERATORS_SYMMETRIC(int, QQuickText::HAlignment, QQuickText::VAlignment)
+
class QTextLine;
class QQuickTextLine : public QObject
{
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index 1d9e3761a2..5dad4d4d42 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -1204,7 +1204,15 @@ void QQuickTextEdit::setCursorVisible(bool on)
/*!
\qmlproperty int QtQuick::TextEdit::cursorPosition
- The position of the cursor in the TextEdit.
+ The position of the cursor in the TextEdit. The cursor is positioned between
+ characters.
+
+ \note The \e characters in this case refer to the string of \l QChar objects,
+ therefore 16-bit Unicode characters, and the position is considered an index
+ into this string. This does not necessarily correspond to individual graphemes
+ in the writing system, as a single grapheme may be represented by multiple
+ Unicode characters, such as in the case of surrogate pairs, linguistic
+ ligatures or diacritics.
*/
int QQuickTextEdit::cursorPosition() const
{
diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h
index 227d8cbf51..88ba2f9d0d 100644
--- a/src/quick/items/qquicktextedit_p.h
+++ b/src/quick/items/qquicktextedit_p.h
@@ -422,6 +422,8 @@ private:
Q_DECLARE_PRIVATE(QQuickTextEdit)
};
+Q_DECLARE_MIXED_ENUM_OPERATORS_SYMMETRIC(int, QQuickTextEdit::HAlignment, QQuickTextEdit::VAlignment)
+
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickTextEdit)
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index bfdb107ef8..9db18d1683 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -518,8 +518,16 @@ void QQuickTextInput::setSelectedTextColor(const QColor &color)
}
/*!
- \qmlproperty enumeration QtQuick::TextInput::horizontalAlignment
\qmlproperty enumeration QtQuick::TextInput::effectiveHorizontalAlignment
+ \readonly
+
+ When using the attached property LayoutMirroring::enabled to mirror application
+ layouts, the horizontal alignment of text will also be mirrored. However, the property
+ \l horizontalAlignment will remain unchanged. To query the effective horizontal alignment
+ of TextInput, use the read-only property \c effectiveHorizontalAlignment.
+*/
+/*!
+ \qmlproperty enumeration QtQuick::TextInput::horizontalAlignment
\qmlproperty enumeration QtQuick::TextInput::verticalAlignment
Sets the horizontal alignment of the text within the TextInput item's
@@ -542,7 +550,7 @@ void QQuickTextInput::setSelectedTextColor(const QColor &color)
When using the attached property LayoutMirroring::enabled to mirror application
layouts, the horizontal alignment of text will also be mirrored. However, the property
\c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
- of TextInput, use the read-only property \c effectiveHorizontalAlignment.
+ of TextInput, use the read-only property \l effectiveHorizontalAlignment.
*/
QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
{
@@ -831,7 +839,20 @@ void QQuickTextInput::setCursorVisible(bool on)
/*!
\qmlproperty int QtQuick::TextInput::cursorPosition
- The position of the cursor in the TextInput.
+ The position of the cursor in the TextInput. The cursor is positioned between
+ characters.
+
+ \note The \e characters in this case refer to the string of \l QChar objects,
+ therefore 16-bit Unicode characters, and the position is considered an index
+ into this string. This does not necessarily correspond to individual graphemes
+ in the writing system, as a single grapheme may be represented by multiple
+ Unicode characters, such as in the case of surrogate pairs, linguistic
+ ligatures or diacritics.
+
+ \l displayText is different if echoMode is set to \l TextInput.Password: then
+ each passwordMaskCharacter is a "narrow" character
+ (the cursorPosition always moves by 1), even if the text in the TextInput is not.
+
*/
int QQuickTextInput::cursorPosition() const
{
@@ -849,6 +870,7 @@ void QQuickTextInput::setCursorPosition(int cp)
/*!
\qmlproperty rectangle QtQuick::TextInput::cursorRectangle
+ \readonly
The rectangle where the standard text cursor is rendered within the text input. Read only.
@@ -890,6 +912,7 @@ QRectF QQuickTextInput::cursorRectangle() const
This property is read-only. To change the selection, use select(start,end),
selectAll(), or selectWord().
+ \readonly
\sa selectionEnd, cursorPosition, selectedText
*/
int QQuickTextInput::selectionStart() const
@@ -905,6 +928,7 @@ int QQuickTextInput::selectionStart() const
This property is read-only. To change the selection, use select(start,end),
selectAll(), or selectWord().
+ \readonly
\sa selectionStart, cursorPosition, selectedText
*/
int QQuickTextInput::selectionEnd() const
@@ -935,6 +959,7 @@ void QQuickTextInput::select(int start, int end)
/*!
\qmlproperty string QtQuick::TextInput::selectedText
+ \readonly
This read-only property provides the text currently selected in the
text input.
@@ -1152,6 +1177,7 @@ void QQuickTextInput::setInputMask(const QString &im)
/*!
\qmlproperty bool QtQuick::TextInput::acceptableInput
+ \readonly
This property is always true unless a validator or input mask has been set.
If a validator or input mask has been set, this property will only be true
@@ -2459,6 +2485,7 @@ void QQuickTextInput::setPersistentSelection(bool on)
/*!
\qmlproperty bool QtQuick::TextInput::canPaste
+ \readonly
Returns true if the TextInput is writable and the content of the clipboard is
suitable for pasting into the TextInput.
@@ -2480,6 +2507,7 @@ bool QQuickTextInput::canPaste() const
/*!
\qmlproperty bool QtQuick::TextInput::canUndo
+ \readonly
Returns true if the TextInput is writable and there are previous operations
that can be undone.
@@ -2493,6 +2521,7 @@ bool QQuickTextInput::canUndo() const
/*!
\qmlproperty bool QtQuick::TextInput::canRedo
+ \readonly
Returns true if the TextInput is writable and there are \l {undo}{undone}
operations that can be redone.
@@ -2506,6 +2535,7 @@ bool QQuickTextInput::canRedo() const
/*!
\qmlproperty real QtQuick::TextInput::contentWidth
+ \readonly
Returns the width of the text, including the width past the width
which is covered due to insufficient wrapping if \l wrapMode is set.
@@ -2519,6 +2549,7 @@ qreal QQuickTextInput::contentWidth() const
/*!
\qmlproperty real QtQuick::TextInput::contentHeight
+ \readonly
Returns the height of the text, including the height past the height
that is covered if the text does not fit within the set height.
@@ -2682,7 +2713,7 @@ void QQuickTextInput::focusOutEvent(QFocusEvent *event)
/*!
\qmlproperty bool QtQuick::TextInput::inputMethodComposing
-
+ \readonly
This property holds whether the TextInput has partial text input from an
input method.
@@ -3458,7 +3489,12 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
for (int i = 0; i < event->attributes().size(); ++i) {
const QInputMethodEvent::Attribute &a = event->attributes().at(i);
if (a.type == QInputMethodEvent::Selection) {
- m_cursor = qBound(0, a.start + a.length, m_text.length());
+ // If we already called internalInsert(), the cursor position will
+ // already be adjusted correctly. The attribute.start does
+ // not seem to take the mask into account, so it will reset cursor
+ // to an invalid position in such case.
+ if (!cursorPositionChanged)
+ m_cursor = qBound(0, a.start + a.length, m_text.length());
if (a.length) {
m_selstart = qMax(0, qMin(a.start, m_text.length()));
m_selend = m_cursor;
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 2b9810ed57..8ab69603ad 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -1494,7 +1494,11 @@ QQuickWindow::QQuickWindow(QQuickWindowPrivate &dd, QWindow *parent)
}
/*!
- \internal
+ Constructs a window for displaying a QML scene, whose rendering will
+ be controlled by the \a control object.
+ Please refer to QQuickRenderControl's documentation for more information.
+
+ \since 5.4
*/
QQuickWindow::QQuickWindow(QQuickRenderControl *control)
: QWindow(*(new QQuickWindowPrivate), nullptr)
@@ -1708,6 +1712,8 @@ QQuickItem *QQuickWindow::contentItem() const
\brief The item which currently has active focus or \c null if there is
no item with active focus.
+
+ \sa QQuickItem::forceActiveFocus(), {Keyboard Focus in Qt Quick}
*/
QQuickItem *QQuickWindow::activeFocusItem() const
{
@@ -2146,6 +2152,15 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce
while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems.at(0))) {
QQuickItem *hoverLeaveItem = hoverItems.takeFirst();
sendHoverEvent(QEvent::HoverLeave, hoverLeaveItem, scenePos, lastScenePos, modifiers, timestamp, accepted);
+ QQuickItemPrivate *hoverLeaveItemPrivate = QQuickItemPrivate::get(hoverLeaveItem);
+ if (hoverLeaveItemPrivate->hasPointerHandlers()) {
+ for (QQuickPointerHandler *handler : hoverLeaveItemPrivate->extra->pointerHandlers) {
+ if (auto *hh = qmlobject_cast<QQuickHoverHandler *>(handler)) {
+ QQuickPointerEvent *pointerEvent = pointerEventInstance(QQuickPointerDevice::genericMouseDevice(), QEvent::MouseMove);
+ pointerEvent->point(0)->cancelPassiveGrab(hh);
+ }
+ }
+ }
}
if (!hoverItems.isEmpty() && hoverItems.at(0) == item) {//Not entering a new Item
@@ -2190,12 +2205,16 @@ bool QQuickWindowPrivate::deliverSinglePointEventUntilAccepted(QQuickPointerEven
QVector<QQuickItem *> targetItems = pointerTargets(contentItem, point, false, false);
for (QQuickItem *item : targetItems) {
+ if (!item->window())
+ continue;
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
event->localize(item);
// Let Pointer Handlers have the first shot
itemPrivate->handlePointerEvent(event);
if (point->isAccepted())
return true;
+ if (!item->window())
+ continue;
QPointF g = item->window()->mapToGlobal(point->scenePosition().toPoint());
#if QT_CONFIG(wheelevent)
// Let the Item have a chance to handle it
@@ -2430,6 +2449,9 @@ void QQuickWindowPrivate::handleMouseEvent(QMouseEvent *event)
Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, event->button(),
event->buttons());
deliverPointerEvent(pointerEventInstance(event));
+#if QT_CONFIG(cursor)
+ updateCursor(event->windowPos());
+#endif
break;
case QEvent::MouseButtonDblClick:
Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick,
@@ -2601,7 +2623,9 @@ QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QEvent *event) con
}
Q_ASSERT(dev);
- return pointerEventInstance(dev, event->type())->reset(event);
+ auto pev = pointerEventInstance(dev, event->type());
+ Q_ASSERT(pev);
+ return pev->reset(event);
}
void QQuickWindowPrivate::deliverPointerEvent(QQuickPointerEvent *event)
diff --git a/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp b/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp
index 7c98e2c1e1..13b4c63c3c 100644
--- a/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp
+++ b/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp
@@ -180,3 +180,5 @@ QSGTexture *Texture::removedFromAtlas() const
}
QT_END_NAMESPACE
+
+#include "moc_qsgcompressedatlastexture_p.cpp"
diff --git a/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp b/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp
index 65abb2a1af..ce433a0411 100644
--- a/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp
+++ b/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp
@@ -382,3 +382,5 @@ QSize QSGCompressedTextureFactory::textureSize() const
}
QT_END_NAMESPACE
+
+#include "moc_qsgcompressedtexture_p.cpp"
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index ec65dce95b..8f24617b24 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -1068,11 +1068,10 @@ static void qsg_wipeBuffer(Buffer *buffer, QOpenGLFunctions *funcs)
free(buffer->data);
}
-static void qsg_wipeBatch(Batch *batch, QOpenGLFunctions *funcs, bool separateIndexBuffer)
+static void qsg_wipeBatch(Batch *batch, QOpenGLFunctions *funcs)
{
qsg_wipeBuffer(&batch->vbo, funcs);
- if (separateIndexBuffer)
- qsg_wipeBuffer(&batch->ibo, funcs);
+ qsg_wipeBuffer(&batch->ibo, funcs);
delete batch->ubuf;
batch->stencilClipState.reset();
delete batch;
@@ -1082,13 +1081,12 @@ Renderer::~Renderer()
{
if (m_rhi || QOpenGLContext::currentContext()) {
// Clean up batches and buffers
- const bool separateIndexBuffer = m_context->separateIndexBuffer();
for (int i = 0; i < m_opaqueBatches.size(); ++i)
- qsg_wipeBatch(m_opaqueBatches.at(i), this, separateIndexBuffer);
+ qsg_wipeBatch(m_opaqueBatches.at(i), this);
for (int i = 0; i < m_alphaBatches.size(); ++i)
- qsg_wipeBatch(m_alphaBatches.at(i), this, separateIndexBuffer);
+ qsg_wipeBatch(m_alphaBatches.at(i), this);
for (int i = 0; i < m_batchPool.size(); ++i)
- qsg_wipeBatch(m_batchPool.at(i), this, separateIndexBuffer);
+ qsg_wipeBatch(m_batchPool.at(i), this);
}
for (Node *n : qAsConst(m_nodes))
@@ -1133,6 +1131,9 @@ void Renderer::releaseCachedResources()
if (m_rhi)
m_rhi->releaseCachedResources();
+
+ m_vertexUploadPool.resize(0);
+ m_indexUploadPool.resize(0);
}
void Renderer::invalidateAndRecycleBatch(Batch *b)
@@ -1159,8 +1160,7 @@ void Renderer::map(Buffer *buffer, int byteSize, bool isIndexBuf)
if (!m_context->hasBrokenIndexBufferObjects() && m_visualizer->mode() == Visualizer::VisualizeNothing) {
// Common case, use a shared memory pool for uploading vertex data to avoid
// excessive reevaluation
- QDataBuffer<char> &pool = m_context->separateIndexBuffer() && isIndexBuf
- ? m_indexUploadPool : m_vertexUploadPool;
+ QDataBuffer<char> &pool = isIndexBuf ? m_indexUploadPool : m_vertexUploadPool;
if (byteSize > pool.size())
pool.resize(byteSize);
buffer->data = pool.data();
@@ -2220,11 +2220,7 @@ void Renderer::uploadBatch(Batch *b)
ibufferSize = unmergedIndexSize;
}
- const bool separateIndexBuffer = m_context->separateIndexBuffer();
- if (separateIndexBuffer)
- map(&b->ibo, ibufferSize, true);
- else
- bufferSize += ibufferSize;
+ map(&b->ibo, ibufferSize, true);
map(&b->vbo, bufferSize);
if (Q_UNLIKELY(debug_upload())) qDebug() << " - batch" << b << " first:" << b->first << " root:"
@@ -2234,9 +2230,7 @@ void Renderer::uploadBatch(Batch *b)
if (b->merged) {
char *vertexData = b->vbo.data;
char *zData = vertexData + b->vertexCount * g->sizeOfVertex();
- char *indexData = separateIndexBuffer
- ? b->ibo.data
- : zData + (int(m_useDepthBuffer) * b->vertexCount * sizeof(float));
+ char *indexData = b->ibo.data;
quint16 iOffset16 = 0;
quint32 iOffset32 = 0;
@@ -2248,8 +2242,8 @@ void Renderer::uploadBatch(Batch *b)
const uint verticesInSetLimit = m_uint32IndexForRhi ? 0xfffffffe : 0xfffe;
int indicesInSet = 0;
b->drawSets.reset();
- int drawSetIndices = separateIndexBuffer ? 0 : indexData - vertexData;
- const char *indexBase = separateIndexBuffer ? b->ibo.data : b->vbo.data;
+ int drawSetIndices = 0;
+ const char *indexBase = b->ibo.data;
b->drawSets << DrawSet(0, zData - vertexData, drawSetIndices);
while (e) {
verticesInSet += e->node->geometry()->vertexCount();
@@ -2283,8 +2277,7 @@ void Renderer::uploadBatch(Batch *b)
}
} else {
char *vboData = b->vbo.data;
- char *iboData = separateIndexBuffer ? b->ibo.data
- : vboData + b->vertexCount * g->sizeOfVertex();
+ char *iboData = b->ibo.data;
Element *e = b->first;
while (e) {
QSGGeometry *g = e->node->geometry();
@@ -2352,9 +2345,7 @@ void Renderer::uploadBatch(Batch *b)
if (!b->drawSets.isEmpty()) {
if (m_uint32IndexForRhi) {
- const quint32 *id = (const quint32 *)(separateIndexBuffer
- ? b->ibo.data
- : b->vbo.data + b->drawSets.at(0).indices);
+ const quint32 *id = (const quint32 *) b->ibo.data;
{
QDebug iDump = qDebug();
iDump << " -- Index Data, count:" << b->indexCount;
@@ -2365,9 +2356,7 @@ void Renderer::uploadBatch(Batch *b)
}
}
} else {
- const quint16 *id = (const quint16 *)(separateIndexBuffer
- ? b->ibo.data
- : b->vbo.data + b->drawSets.at(0).indices);
+ const quint16 *id = (const quint16 *) b->ibo.data;
{
QDebug iDump = qDebug();
iDump << " -- Index Data, count:" << b->indexCount;
@@ -2388,8 +2377,7 @@ void Renderer::uploadBatch(Batch *b)
#endif // QT_NO_DEBUG_OUTPUT
unmap(&b->vbo);
- if (separateIndexBuffer)
- unmap(&b->ibo, true);
+ unmap(&b->ibo, true);
if (Q_UNLIKELY(debug_upload())) qDebug() << " --- vertex/index buffers unmapped, batch upload completed...";
@@ -3049,7 +3037,7 @@ void Renderer::renderMergedBatch(const Batch *batch) // legacy (GL-only)
glBindBuffer(GL_ARRAY_BUFFER, batch->vbo.id);
char *indexBase = nullptr;
- const Buffer *indexBuf = m_context->separateIndexBuffer() ? &batch->ibo : &batch->vbo;
+ const Buffer *indexBuf = &batch->ibo;
if (m_context->hasBrokenIndexBufferObjects()) {
indexBase = indexBuf->data;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
@@ -3142,8 +3130,7 @@ void Renderer::renderUnmergedBatch(const Batch *batch) // legacy (GL-only)
glBindBuffer(GL_ARRAY_BUFFER, batch->vbo.id);
char *indexBase = nullptr;
- const bool separateIndexBuffer = m_context->separateIndexBuffer();
- const Buffer *indexBuf = separateIndexBuffer ? &batch->ibo : &batch->vbo;
+ const Buffer *indexBuf = &batch->ibo;
if (batch->indexCount) {
if (m_context->hasBrokenIndexBufferObjects()) {
indexBase = indexBuf->data;
@@ -3173,9 +3160,6 @@ void Renderer::renderUnmergedBatch(const Batch *batch) // legacy (GL-only)
int vOffset = 0;
char *iOffset = indexBase;
- if (!separateIndexBuffer)
- iOffset += batch->vertexCount * gn->geometry()->sizeOfVertex();
-
QMatrix4x4 rootMatrix = batch->root ? qsg_matrixForRoot(batch->root) : QMatrix4x4();
while (e) {
@@ -4006,6 +3990,17 @@ void Renderer::renderBatches()
if (m_useDepthBuffer) {
glClearDepthf(1); // calls glClearDepth() under the hood for desktop OpenGL
+ glDepthMask(true);
+ }
+ glColorMask(true, true, true, true);
+ glDisable(GL_SCISSOR_TEST);
+
+ bindable()->clear(clearMode());
+
+ if (m_renderPassRecordingCallbacks.start)
+ m_renderPassRecordingCallbacks.start(m_renderPassRecordingCallbacks.userData);
+
+ if (m_useDepthBuffer) {
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDepthMask(true);
@@ -4019,11 +4014,6 @@ void Renderer::renderBatches()
glDisable(GL_SCISSOR_TEST);
glDisable(GL_STENCIL_TEST);
- bindable()->clear(clearMode());
-
- if (m_renderPassRecordingCallbacks.start)
- m_renderPassRecordingCallbacks.start(m_renderPassRecordingCallbacks.userData);
-
if (Q_LIKELY(renderOpaque)) {
for (int i=0; i<m_opaqueBatches.size(); ++i) {
Batch *b = m_opaqueBatches.at(i);
@@ -4339,7 +4329,7 @@ void Renderer::render()
if (largestVBO * 2 < m_vertexUploadPool.size())
m_vertexUploadPool.resize(largestVBO * 2);
- if (m_context->separateIndexBuffer() && largestIBO * 2 < m_indexUploadPool.size())
+ if (largestIBO * 2 < m_indexUploadPool.size())
m_indexUploadPool.resize(largestIBO * 2);
renderBatches();
diff --git a/src/quick/scenegraph/coreapi/qsggeometry.h b/src/quick/scenegraph/coreapi/qsggeometry.h
index d17915a842..685ac1cd95 100644
--- a/src/quick/scenegraph/coreapi/qsggeometry.h
+++ b/src/quick/scenegraph/coreapi/qsggeometry.h
@@ -202,6 +202,7 @@ public:
void setLineWidth(float w);
private:
+ Q_DISABLE_COPY_MOVE(QSGGeometry)
friend class QSGGeometryData;
int m_drawing_mode;
diff --git a/src/quick/scenegraph/coreapi/qsgmaterialrhishader.cpp b/src/quick/scenegraph/coreapi/qsgmaterialrhishader.cpp
index c5cbd0c979..d2eb22f45a 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterialrhishader.cpp
+++ b/src/quick/scenegraph/coreapi/qsgmaterialrhishader.cpp
@@ -105,7 +105,7 @@ void QSGMaterialRhiShaderPrivate::prepare(QShader::Variant vertexShaderVariant)
ubufBinding = -1;
ubufSize = 0;
ubufStages = { };
- memset(combinedImageSamplerBindings, 0, sizeof(combinedImageSamplerBindings));
+ memset(static_cast<void *>(combinedImageSamplerBindings), 0, sizeof(combinedImageSamplerBindings));
vertexShader = fragmentShader = nullptr;
masterUniformData.clear();
diff --git a/src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp b/src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp
index 9282b6c308..c7af996a30 100644
--- a/src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp
@@ -130,7 +130,7 @@ void OpenGLVisualizer::visualizeBatch(Batch *b)
if (b->merged) {
shader->setUniformValue(shader->matrix, matrix);
- const char *dataStart = m_renderer->m_context->separateIndexBuffer() ? b->ibo.data : b->vbo.data;
+ const char *dataStart = b->ibo.data;
for (int ds=0; ds<b->drawSets.size(); ++ds) {
const DrawSet &set = b->drawSets.at(ds);
m_funcs->glVertexAttribPointer(a.position, 2, a.type, false, g->sizeOfVertex(),
diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h
index 742a4d03b2..04f1f2732c 100644
--- a/src/quick/scenegraph/qsgadaptationlayer_p.h
+++ b/src/quick/scenegraph/qsgadaptationlayer_p.h
@@ -465,9 +465,9 @@ public:
{
return pixelSize / QT_DISTANCEFIELD_BASEFONTSIZE(m_doubleGlyphResolution);
}
- int distanceFieldRadius() const
+ qreal distanceFieldRadius() const
{
- return QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) / QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution);
+ return QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution));
}
int glyphCount() const { return m_glyphCount; }
bool doubleGlyphResolution() const { return m_doubleGlyphResolution; }
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
index 0fd6581dc4..d6834b554e 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -119,7 +119,8 @@ public:
protected:
void initialize() override;
- int m_matrix_id;
+ int m_projectionMatrix_id;
+ int m_modelViewMatrix_id;
int m_color_id;
int m_textureScale_id;
float m_devicePixelRatio;
@@ -135,7 +136,8 @@ char const *const *QSGTextMaskShader::attributeNames() const
QSGTextMaskShader::QSGTextMaskShader(QFontEngine::GlyphFormat glyphFormat)
: QSGMaterialShader(*new QSGMaterialShaderPrivate)
- , m_matrix_id(-1)
+ , m_projectionMatrix_id(-1)
+ , m_modelViewMatrix_id(-1)
, m_color_id(-1)
, m_textureScale_id(-1)
, m_glyphFormat(glyphFormat)
@@ -146,7 +148,8 @@ QSGTextMaskShader::QSGTextMaskShader(QFontEngine::GlyphFormat glyphFormat)
void QSGTextMaskShader::initialize()
{
- m_matrix_id = program()->uniformLocation("matrix");
+ m_projectionMatrix_id = program()->uniformLocation("projectionMatrix");
+ m_modelViewMatrix_id = program()->uniformLocation("modelViewMatrix");
m_color_id = program()->uniformLocation("color");
m_textureScale_id = program()->uniformLocation("textureScale");
m_devicePixelRatio = (float) qsg_device_pixel_ratio(QOpenGLContext::currentContext());
@@ -184,8 +187,10 @@ void QSGTextMaskShader::updateState(const RenderState &state, QSGMaterial *newEf
program()->setUniformValue("dpr", m_devicePixelRatio);
}
- if (state.isMatrixDirty())
- program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+ if (state.isMatrixDirty()) {
+ program()->setUniformValue(m_projectionMatrix_id, state.projectionMatrix());
+ program()->setUniformValue(m_modelViewMatrix_id, state.modelViewMatrix());
+ }
}
class QSG8BitTextMaskShader : public QSGTextMaskShader
@@ -387,8 +392,10 @@ void QSGStyledTextShader::updateState(const RenderState &state,
}
}
- if (state.isMatrixDirty())
- program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+ if (state.isMatrixDirty()) {
+ program()->setUniformValue(m_projectionMatrix_id, state.projectionMatrix());
+ program()->setUniformValue(m_modelViewMatrix_id, state.modelViewMatrix());
+ }
}
class QSGOutlinedTextShader : public QSGStyledTextShader
@@ -811,8 +818,11 @@ void QSGTextMaskMaterial::populate(const QPointF &p,
QTextureGlyphCache *cache = glyphCache();
QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
- cache->populate(fontD->fontEngine, glyphIndexes.size(), glyphIndexes.constData(),
- fixedPointPositions.data());
+ cache->populate(fontD->fontEngine,
+ glyphIndexes.size(),
+ glyphIndexes.constData(),
+ fixedPointPositions.data(),
+ true);
cache->fillInPendingGlyphs();
int margin = fontD->fontEngine->glyphMargin(cache->glyphFormat());
@@ -832,9 +842,11 @@ void QSGTextMaskMaterial::populate(const QPointF &p,
bool supportsSubPixelPositions = fontD->fontEngine->supportsSubPixelPositions();
for (int i=0; i<glyphIndexes.size(); ++i) {
QPointF glyphPosition = glyphPositions.at(i) + position;
+ QFixedPoint fixedPointPosition = fixedPointPositions.at(i);
+
QFixed subPixelPosition;
if (supportsSubPixelPositions)
- subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(glyphPosition.x()));
+ subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(fixedPointPosition.x.toReal() * glyphCacheScaleX));
QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphIndexes.at(i), subPixelPosition);
const QTextureGlyphCache::Coord &c = cache->coords.value(glyph);
diff --git a/src/quick/scenegraph/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
index bf7bb052bb..0e11a062de 100644
--- a/src/quick/scenegraph/qsgdefaultrendercontext.cpp
+++ b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
@@ -415,21 +415,6 @@ QSGDefaultRenderContext *QSGDefaultRenderContext::from(QOpenGLContext *context)
return qobject_cast<QSGDefaultRenderContext *>(context->property(QSG_RENDERCONTEXT_PROPERTY).value<QObject *>());
}
-bool QSGDefaultRenderContext::separateIndexBuffer() const
-{
- if (m_rhi)
- return true;
-
- // WebGL: A given WebGLBuffer object may only be bound to one of
- // the ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER target in its
- // lifetime. An attempt to bind a buffer object to the other
- // target will generate an INVALID_OPERATION error, and the
- // current binding will remain untouched.
- static const bool isWebGL = (qGuiApp->platformName().compare(QLatin1String("webgl")) == 0
- || qGuiApp->platformName().compare(QLatin1String("wasm")) == 0);
- return isWebGL;
-}
-
void QSGDefaultRenderContext::preprocess()
{
for (auto it = m_glyphCaches.begin(); it != m_glyphCaches.end(); ++it) {
diff --git a/src/quick/scenegraph/qsgdefaultrendercontext_p.h b/src/quick/scenegraph/qsgdefaultrendercontext_p.h
index e90a11eda6..6da67264d1 100644
--- a/src/quick/scenegraph/qsgdefaultrendercontext_p.h
+++ b/src/quick/scenegraph/qsgdefaultrendercontext_p.h
@@ -140,7 +140,6 @@ public:
bool hasBrokenIndexBufferObjects() const { return m_brokenIBOs; }
int maxTextureSize() const override { return m_maxTextureSize; }
- bool separateIndexBuffer() const;
int msaaSampleCount() const { return m_initParams.sampleCount; }
diff --git a/src/quick/scenegraph/qsgopengldistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgopengldistancefieldglyphcache.cpp
index b6b6f3b057..6e9894b10b 100644
--- a/src/quick/scenegraph/qsgopengldistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgopengldistancefieldglyphcache.cpp
@@ -122,7 +122,7 @@ void QSGOpenGLDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs
// We need to add a buffer to avoid glyphs that overlap the border between two
// textures causing the height of the textures to extend beyond the limit.
- m_maxTextureHeight = m_maxTextureWidth - (qCeil(m_referenceFont.pixelSize() * scaleFactor) + distanceFieldRadius() * 2 + padding * 2);
+ m_maxTextureHeight = m_maxTextureWidth - (qCeil(m_referenceFont.pixelSize() * scaleFactor + distanceFieldRadius() * 2) + padding * 2);
}
if (m_areaAllocator == nullptr)
@@ -132,8 +132,8 @@ void QSGOpenGLDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs
glyph_t glyphIndex = *it;
QRectF boundingRect = glyphData(glyphIndex).boundingRect;
- int glyphWidth = qCeil(boundingRect.width()) + distanceFieldRadius() * 2;
- int glyphHeight = qCeil(boundingRect.height()) + distanceFieldRadius() * 2;
+ int glyphWidth = qCeil(boundingRect.width() + distanceFieldRadius()) * 2;
+ int glyphHeight = qCeil(boundingRect.height() + distanceFieldRadius()) * 2;
QSize glyphSize(glyphWidth + padding * 2, glyphHeight + padding * 2);
QRect alloc = m_areaAllocator->allocate(glyphSize);
@@ -144,8 +144,8 @@ void QSGOpenGLDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs
TexCoord unusedCoord = glyphTexCoord(unusedGlyph);
QRectF unusedGlyphBoundingRect = glyphData(unusedGlyph).boundingRect;
- int unusedGlyphWidth = qCeil(unusedGlyphBoundingRect.width()) + distanceFieldRadius() * 2;
- int unusedGlyphHeight = qCeil(unusedGlyphBoundingRect.height()) + distanceFieldRadius() * 2;
+ int unusedGlyphWidth = qCeil(unusedGlyphBoundingRect.width() + distanceFieldRadius()) * 2;
+ int unusedGlyphHeight = qCeil(unusedGlyphBoundingRect.height() + distanceFieldRadius()) * 2;
m_areaAllocator->deallocate(QRect(unusedCoord.x - padding,
unusedCoord.y - padding,
padding * 2 + unusedGlyphWidth,
diff --git a/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp
index 53b6fe117f..2325a2665b 100644
--- a/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp
@@ -86,8 +86,8 @@ void QSGRhiDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs)
int padding = QSG_RHI_DISTANCEFIELD_GLYPH_CACHE_PADDING;
QRectF boundingRect = glyphData(glyphIndex).boundingRect;
- int glyphWidth = qCeil(boundingRect.width()) + distanceFieldRadius() * 2;
- int glyphHeight = qCeil(boundingRect.height()) + distanceFieldRadius() * 2;
+ int glyphWidth = qCeil(boundingRect.width() + distanceFieldRadius() * 2);
+ int glyphHeight = qCeil(boundingRect.height() + distanceFieldRadius() * 2);
QSize glyphSize(glyphWidth + padding * 2, glyphHeight + padding * 2);
QRect alloc = m_areaAllocator->allocate(glyphSize);
@@ -98,8 +98,8 @@ void QSGRhiDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs)
TexCoord unusedCoord = glyphTexCoord(unusedGlyph);
QRectF unusedGlyphBoundingRect = glyphData(unusedGlyph).boundingRect;
- int unusedGlyphWidth = qCeil(unusedGlyphBoundingRect.width()) + distanceFieldRadius() * 2;
- int unusedGlyphHeight = qCeil(unusedGlyphBoundingRect.height()) + distanceFieldRadius() * 2;
+ int unusedGlyphWidth = qCeil(unusedGlyphBoundingRect.width() + distanceFieldRadius() * 2);
+ int unusedGlyphHeight = qCeil(unusedGlyphBoundingRect.height() + distanceFieldRadius() * 2);
m_areaAllocator->deallocate(QRect(unusedCoord.x - padding,
unusedCoord.y - padding,
padding * 2 + unusedGlyphWidth,
@@ -446,7 +446,7 @@ bool QSGRhiDistanceFieldGlyphCache::loadPregeneratedCache(const QRawFont &font)
const char *textureRecord = allocatorData;
for (int i = 0; i < textureCount; ++i, textureRecord += Qtdf::TextureRecordSize) {
- if (textureRecord + Qtdf::TextureRecordSize > qtdfTableEnd) {
+ if (qtdfTableEnd - textureRecord < Qtdf::TextureRecordSize) {
qWarning("qtdf table too small in font '%s'.",
qPrintable(font.familyName()));
return false;
@@ -462,7 +462,7 @@ bool QSGRhiDistanceFieldGlyphCache::loadPregeneratedCache(const QRawFont &font)
const char *glyphRecord = textureRecord;
for (quint32 i = 0; i < glyphCount; ++i, glyphRecord += Qtdf::GlyphRecordSize) {
- if (glyphRecord + Qtdf::GlyphRecordSize > qtdfTableEnd) {
+ if (qtdfTableEnd - glyphRecord < Qtdf:: GlyphRecordSize) {
qWarning("qtdf table too small in font '%s'.",
qPrintable(font.familyName()));
return false;
@@ -512,8 +512,8 @@ bool QSGRhiDistanceFieldGlyphCache::loadPregeneratedCache(const QRawFont &font)
int width = texInfo->allocatedArea.width();
int height = texInfo->allocatedArea.height();
- qint64 size = width * height;
- if (reinterpret_cast<const char *>(textureData + size) > qtdfTableEnd) {
+ qint64 size = qint64(width) * height;
+ if (qtdfTableEnd - reinterpret_cast<const char *>(textureData) < size) {
qWarning("qtdf table too small in font '%s'.",
qPrintable(font.familyName()));
return false;
diff --git a/src/quick/scenegraph/qsgrhishadereffectnode.cpp b/src/quick/scenegraph/qsgrhishadereffectnode.cpp
index e86dae7c09..b0d3ca78f5 100644
--- a/src/quick/scenegraph/qsgrhishadereffectnode.cpp
+++ b/src/quick/scenegraph/qsgrhishadereffectnode.cpp
@@ -572,10 +572,10 @@ void QSGRhiShaderEffectMaterial::updateTextureProviders(bool layoutChange)
QSGRhiShaderEffectNode::QSGRhiShaderEffectNode(QSGDefaultRenderContext *rc, QSGRhiGuiThreadShaderEffectManager *mgr)
: QSGShaderEffectNode(mgr),
- m_rc(rc),
m_mgr(mgr),
m_material(this)
{
+ Q_UNUSED(rc);
setFlag(UsePreprocess, true);
setMaterial(&m_material);
}
@@ -884,3 +884,5 @@ bool QSGRhiGuiThreadShaderEffectManager::reflect(ShaderInfo *result)
}
QT_END_NAMESPACE
+
+#include "moc_qsgrhishadereffectnode_p.cpp"
diff --git a/src/quick/scenegraph/qsgrhishadereffectnode_p.h b/src/quick/scenegraph/qsgrhishadereffectnode_p.h
index 26460d24b2..3c382743ee 100644
--- a/src/quick/scenegraph/qsgrhishadereffectnode_p.h
+++ b/src/quick/scenegraph/qsgrhishadereffectnode_p.h
@@ -139,7 +139,6 @@ private Q_SLOTS:
void handleTextureProviderDestroyed(QObject *object);
private:
- QSGDefaultRenderContext *m_rc;
QSGRhiGuiThreadShaderEffectManager *m_mgr;
QSGRhiShaderEffectMaterial m_material;
};
diff --git a/src/quick/scenegraph/qsgrhitextureglyphcache.cpp b/src/quick/scenegraph/qsgrhitextureglyphcache.cpp
index 89c9ea4d5b..c35d5b0705 100644
--- a/src/quick/scenegraph/qsgrhitextureglyphcache.cpp
+++ b/src/quick/scenegraph/qsgrhitextureglyphcache.cpp
@@ -233,7 +233,10 @@ void QSGRhiTextureGlyphCache::endFillTexture()
int QSGRhiTextureGlyphCache::glyphPadding() const
{
- return 1;
+ if (m_format == QFontEngine::Format_Mono)
+ return 8;
+ else
+ return 1;
}
int QSGRhiTextureGlyphCache::maxTextureWidth() const
diff --git a/src/quick/scenegraph/shaders/outlinedtext.vert b/src/quick/scenegraph/shaders/outlinedtext.vert
index 9df832de3c..42fa577063 100644
--- a/src/quick/scenegraph/shaders/outlinedtext.vert
+++ b/src/quick/scenegraph/shaders/outlinedtext.vert
@@ -1,4 +1,5 @@
-uniform highp mat4 matrix;
+uniform highp mat4 modelViewMatrix;
+uniform highp mat4 projectionMatrix;
uniform highp vec2 textureScale;
uniform highp vec2 shift;
uniform highp float dpr;
@@ -19,6 +20,6 @@ void main()
sCoordDown = (tCoord - vec2(0.0, 1.0)) * textureScale;
sCoordLeft = (tCoord - vec2(-1.0, 0.0)) * textureScale;
sCoordRight = (tCoord - vec2(1.0, 0.0)) * textureScale;
- vec3 dprSnapPos = floor(vCoord.xyz * dpr + 0.5) / dpr;
- gl_Position = matrix * vec4(dprSnapPos, vCoord.w);
-} \ No newline at end of file
+ vec4 xformed = modelViewMatrix * vCoord;
+ gl_Position = projectionMatrix * vec4(floor(xformed.xyz * dpr + 0.5) / dpr, xformed.w);
+}
diff --git a/src/quick/scenegraph/shaders/outlinedtext_core.vert b/src/quick/scenegraph/shaders/outlinedtext_core.vert
index a854355460..50a1371e89 100644
--- a/src/quick/scenegraph/shaders/outlinedtext_core.vert
+++ b/src/quick/scenegraph/shaders/outlinedtext_core.vert
@@ -9,7 +9,8 @@ out vec2 sCoordDown;
out vec2 sCoordLeft;
out vec2 sCoordRight;
-uniform mat4 matrix;
+uniform mat4 modelViewMatrix;
+uniform mat4 projectionMatrix;
uniform vec2 textureScale;
uniform vec2 shift;
uniform float dpr;
@@ -21,6 +22,6 @@ void main()
sCoordDown = (tCoord - vec2(0.0, 1.0)) * textureScale;
sCoordLeft = (tCoord - vec2(-1.0, 0.0)) * textureScale;
sCoordRight = (tCoord - vec2(1.0, 0.0)) * textureScale;
- vec3 dprSnapPos = floor(vCoord.xyz * dpr + 0.5) / dpr;
- gl_Position = matrix * vec4(dprSnapPos, vCoord.w);
-} \ No newline at end of file
+ vec4 xformed = modelViewMatrix * vCoord;
+ gl_Position = projectionMatrix * vec4(floor(xformed.xyz * dpr + 0.5) / dpr, xformed.w);
+}
diff --git a/src/quick/scenegraph/shaders/styledtext.vert b/src/quick/scenegraph/shaders/styledtext.vert
index 29c9902609..dc87dadd5f 100644
--- a/src/quick/scenegraph/shaders/styledtext.vert
+++ b/src/quick/scenegraph/shaders/styledtext.vert
@@ -1,4 +1,5 @@
-uniform highp mat4 matrix;
+uniform highp mat4 modelViewMatrix;
+uniform highp mat4 projectionMatrix;
uniform highp vec2 textureScale;
uniform highp vec2 shift;
uniform highp float dpr;
@@ -13,6 +14,6 @@ void main()
{
sampleCoord = tCoord * textureScale;
shiftedSampleCoord = (tCoord - shift) * textureScale;
- vec3 dprSnapPos = floor(vCoord.xyz * dpr + 0.5) / dpr;
- gl_Position = matrix * vec4(dprSnapPos, vCoord.w);
+ vec4 xformed = modelViewMatrix * vCoord;
+ gl_Position = projectionMatrix * vec4(floor(xformed.xyz * dpr + 0.5) / dpr, xformed.w);
}
diff --git a/src/quick/scenegraph/shaders/styledtext_core.vert b/src/quick/scenegraph/shaders/styledtext_core.vert
index 04a0e88da8..d9a81bf06f 100644
--- a/src/quick/scenegraph/shaders/styledtext_core.vert
+++ b/src/quick/scenegraph/shaders/styledtext_core.vert
@@ -6,7 +6,8 @@ in vec2 tCoord;
out vec2 sampleCoord;
out vec2 shiftedSampleCoord;
-uniform mat4 matrix;
+uniform mat4 modelViewMatrix;
+uniform mat4 projectionMatrix;
uniform vec2 textureScale;
uniform vec2 shift;
uniform float dpr;
@@ -15,6 +16,6 @@ void main()
{
sampleCoord = tCoord * textureScale;
shiftedSampleCoord = (tCoord - shift) * textureScale;
- vec3 dprSnapPos = floor(vCoord.xyz * dpr + 0.5) / dpr;
- gl_Position = matrix * vec4(dprSnapPos, vCoord.w);
+ vec4 xformed = modelViewMatrix * vCoord;
+ gl_Position = projectionMatrix * vec4(floor(xformed.xyz * dpr + 0.5) / dpr, xformed.w);
}
diff --git a/src/quick/scenegraph/shaders/textmask.vert b/src/quick/scenegraph/shaders/textmask.vert
index 1692159d2c..7f418b0895 100644
--- a/src/quick/scenegraph/shaders/textmask.vert
+++ b/src/quick/scenegraph/shaders/textmask.vert
@@ -1,4 +1,5 @@
-uniform highp mat4 matrix;
+uniform highp mat4 modelViewMatrix;
+uniform highp mat4 projectionMatrix;
uniform highp vec2 textureScale;
uniform highp float dpr;
@@ -10,6 +11,6 @@ varying highp vec2 sampleCoord;
void main()
{
sampleCoord = tCoord * textureScale;
- vec3 dprSnapPos = floor(vCoord.xyz * dpr + 0.5) / dpr;
- gl_Position = matrix * vec4(dprSnapPos, vCoord.w);
+ vec4 xformed = modelViewMatrix * vCoord;
+ gl_Position = projectionMatrix * vec4(floor(xformed.xyz * dpr + 0.5) / dpr, xformed.w);
}
diff --git a/src/quick/scenegraph/shaders/textmask_core.vert b/src/quick/scenegraph/shaders/textmask_core.vert
index b0efc1e731..1f88974aed 100644
--- a/src/quick/scenegraph/shaders/textmask_core.vert
+++ b/src/quick/scenegraph/shaders/textmask_core.vert
@@ -5,13 +5,14 @@ in vec2 tCoord;
out vec2 sampleCoord;
-uniform mat4 matrix;
+uniform mat4 modelViewMatrix;
+uniform mat4 projectionMatrix;
uniform vec2 textureScale;
uniform float dpr;
void main()
{
sampleCoord = tCoord * textureScale;
- vec3 dprSnapPos = floor(vCoord.xyz * dpr + 0.5) / dpr;
- gl_Position = matrix * vec4(dprSnapPos, vCoord.w);
+ vec4 xformed = modelViewMatrix * vCoord;
+ gl_Position = projectionMatrix * vec4(floor(xformed.xyz * dpr + 0.5) / dpr, xformed.w);
}
diff --git a/src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsb b/src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsb
index c493996375..6eee3f01d6 100644
--- a/src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsb b/src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsb
index 3f8489bfe6..d81bb2f26d 100644
--- a/src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsb b/src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsb
index f721207325..6ebb3342ac 100644
--- a/src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsb b/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsb
index 93ac0124be..e29f734c33 100644
--- a/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsb b/src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsb
index 1756ee9d4b..071abd2f88 100644
--- a/src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsb b/src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsb
index b8d38bdff4..dd159d008d 100644
--- a/src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsb b/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsb
index f44b92dc28..393b1608e9 100644
--- a/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/styledtext.frag.qsb b/src/quick/scenegraph/shaders_ng/styledtext.frag.qsb
index b0461a686c..5b45142201 100644
--- a/src/quick/scenegraph/shaders_ng/styledtext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/styledtext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/styledtext.vert.qsb b/src/quick/scenegraph/shaders_ng/styledtext.vert.qsb
index 18e4685d21..e2a5859bfc 100644
--- a/src/quick/scenegraph/shaders_ng/styledtext.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/styledtext.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsb b/src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsb
index 3d9b5a0bdd..c3aa6c068a 100644
--- a/src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/textmask.frag.qsb b/src/quick/scenegraph/shaders_ng/textmask.frag.qsb
index cfae9575da..a4341d8915 100644
--- a/src/quick/scenegraph/shaders_ng/textmask.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/textmask.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/textmask.vert.qsb b/src/quick/scenegraph/shaders_ng/textmask.vert.qsb
index 2ea425e1c0..4ca3b874d0 100644
--- a/src/quick/scenegraph/shaders_ng/textmask.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/textmask.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/util/qsgplaintexture.cpp b/src/quick/scenegraph/util/qsgplaintexture.cpp
index f00918bb4e..7c3cf90325 100644
--- a/src/quick/scenegraph/util/qsgplaintexture.cpp
+++ b/src/quick/scenegraph/util/qsgplaintexture.cpp
@@ -466,3 +466,5 @@ void QSGPlainTexturePrivate::updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch
}
QT_END_NAMESPACE
+
+#include "moc_qsgplaintexture_p.cpp"
diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp
index 2ae8a5a2aa..f027e9fafe 100644
--- a/src/quick/util/qquickanimatorjob.cpp
+++ b/src/quick/util/qquickanimatorjob.cpp
@@ -285,6 +285,17 @@ qreal QQuickAnimatorJob::progress(int time) const
return m_easing.valueForProgress((m_duration == 0) ? qreal(1) : qreal(time) / qreal(m_duration));
}
+void QQuickAnimatorJob::boundValue()
+{
+ qreal rangeMin = m_from;
+ qreal rangeMax = m_to;
+ if (m_from > m_to) {
+ rangeMax = m_from;
+ rangeMin = m_to;
+ }
+ m_value = qBound(rangeMin, m_value, rangeMax);
+}
+
qreal QQuickAnimatorJob::value() const
{
qreal value = m_to;
diff --git a/src/quick/util/qquickanimatorjob_p.h b/src/quick/util/qquickanimatorjob_p.h
index 522540bcbc..a31cd08032 100644
--- a/src/quick/util/qquickanimatorjob_p.h
+++ b/src/quick/util/qquickanimatorjob_p.h
@@ -122,10 +122,16 @@ public:
virtual void setTarget(QQuickItem *target);
QQuickItem *target() const { return m_target; }
- void setFrom(qreal from) { m_from = from; }
+ void setFrom(qreal from) {
+ m_from = from;
+ boundValue();
+ }
qreal from() const { return m_from; }
- void setTo(qreal to) { m_to = to; }
+ void setTo(qreal to) {
+ m_to = to;
+ boundValue();
+ }
qreal to() const { return m_to; }
void setDuration(int duration) { m_duration = duration; }
@@ -171,6 +177,7 @@ protected:
void debugAnimation(QDebug d) const override;
qreal progress(int time) const;
+ void boundValue();
QPointer<QQuickItem> m_target;
QQuickAnimatorController *m_controller;
diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp
index 1cb30f5a8d..7a47f132fe 100644
--- a/src/quick/util/qquickpropertychanges.cpp
+++ b/src/quick/util/qquickpropertychanges.cpp
@@ -239,18 +239,22 @@ public:
void QQuickPropertyChangesParser::verifyList(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding)
{
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- error(compilationUnit->objectAt(binding->value.objectIndex), QQuickPropertyChanges::tr("PropertyChanges does not support creating state-specific objects."));
- return;
- }
-
- if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty
- || binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_Object:
+ error(compilationUnit->objectAt(binding->value.objectIndex),
+ QQuickPropertyChanges::tr(
+ "PropertyChanges does not support creating state-specific objects."));
+ break;
+ case QV4::CompiledData::Binding::Type_GroupProperty:
+ case QV4::CompiledData::Binding::Type_AttachedProperty: {
const QV4::CompiledData::Object *subObj = compilationUnit->objectAt(binding->value.objectIndex);
const QV4::CompiledData::Binding *subBinding = subObj->bindingTable();
- for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding) {
+ for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding)
verifyList(compilationUnit, subBinding);
- }
+ break;
+ }
+ default:
+ break;
}
}
@@ -273,8 +277,9 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix,
QString propertyName = propertyPrefix + compilationUnit->stringAt(binding->propertyNameIndex);
- if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty
- || binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_GroupProperty:
+ case QV4::CompiledData::Binding::Type_AttachedProperty: {
QString pre = propertyName + QLatin1Char('.');
const QV4::CompiledData::Object *subObj = compilationUnit->objectAt(binding->value.objectIndex);
const QV4::CompiledData::Binding *subBinding = subObj->bindingTable();
@@ -283,6 +288,9 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix,
}
return;
}
+ default:
+ break;
+ }
if (propertyName.count() >= 3 &&
propertyName.at(0) == QLatin1Char('o') &&
@@ -299,7 +307,8 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix,
}
}
- if (binding->type == QV4::CompiledData::Binding::Type_Script || binding->isTranslationBinding()) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Script
+ || binding->isTranslationBinding()) {
QUrl url = QUrl();
int line = -1;
int column = -1;
@@ -323,7 +332,7 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix,
}
QVariant var;
- switch (binding->type) {
+ switch (binding->type()) {
case QV4::CompiledData::Binding::Type_Script:
case QV4::CompiledData::Binding::Type_Translation:
case QV4::CompiledData::Binding::Type_TranslationById:
diff --git a/src/quick/util/qquicksmoothedanimation.cpp b/src/quick/util/qquicksmoothedanimation.cpp
index 254b1af0a2..d511dc0562 100644
--- a/src/quick/util/qquicksmoothedanimation.cpp
+++ b/src/quick/util/qquicksmoothedanimation.cpp
@@ -569,4 +569,6 @@ void QQuickSmoothedAnimation::setMaximumEasingTime(int v)
QT_END_NAMESPACE
+#include "moc_qquicksmoothedanimation_p_p.cpp"
+
#include "moc_qquicksmoothedanimation_p.cpp"
diff --git a/src/quick/util/qquickstategroup.cpp b/src/quick/util/qquickstategroup.cpp
index 2109aafc10..7cb3138618 100644
--- a/src/quick/util/qquickstategroup.cpp
+++ b/src/quick/util/qquickstategroup.cpp
@@ -376,7 +376,14 @@ bool QQuickStateGroupPrivate::updateAutoState()
QQuickState *state = states.at(ii);
if (state->isWhenKnown()) {
if (state->isNamed()) {
- if (state->when()) {
+ bool whenValue = state->when();
+ const QQmlProperty whenProp(state, QLatin1String("when"));
+ const auto potentialWhenBinding = QQmlPropertyPrivate::binding(whenProp);
+ // if there is a binding, the value in when might not be up-to-date at this point
+ // so we manually reevaluate the binding
+ if (auto abstractBinding = dynamic_cast<QQmlBinding *>(potentialWhenBinding))
+ whenValue = abstractBinding->evaluate().toBool();
+ if (whenValue) {
if (stateChangeDebug())
qWarning() << "Setting auto state due to expression";
if (currentState != state->name()) {
diff --git a/src/quick/util/qquickstyledtext.cpp b/src/quick/util/qquickstyledtext.cpp
index d531fc9205..a25af90414 100644
--- a/src/quick/util/qquickstyledtext.cpp
+++ b/src/quick/util/qquickstyledtext.cpp
@@ -564,6 +564,8 @@ void QQuickStyledTextPrivate::parseEntity(const QChar *&ch, const QString &textI
textOut += QChar(60);
else if (entity == QLatin1String("amp"))
textOut += QChar(38);
+ else if (entity == QLatin1String("apos"))
+ textOut += QChar(39);
else if (entity == QLatin1String("quot"))
textOut += QChar(34);
else if (entity == QLatin1String("nbsp"))
diff --git a/src/quick/util/qquicktimeline.cpp b/src/quick/util/qquicktimeline.cpp
index 7ec7c827eb..949724e87c 100644
--- a/src/quick/util/qquicktimeline.cpp
+++ b/src/quick/util/qquicktimeline.cpp
@@ -53,6 +53,8 @@
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcTl, "qt.quick.timeline")
+
struct Update {
Update(QQuickTimeLineValue *_g, qreal _v)
: g(_g), v(_v) {}
@@ -513,6 +515,7 @@ void QQuickTimeLine::reset(QQuickTimeLineValue &timeLineValue)
qWarning() << "QQuickTimeLine: Cannot reset a QQuickTimeLineValue owned by another timeline.";
return;
}
+ qCDebug(lcTl) << static_cast<QObject*>(this) << timeLineValue.value();
remove(&timeLineValue);
timeLineValue._t = nullptr;
}
@@ -954,3 +957,5 @@ QQuickTimeLineObject *QQuickTimeLineCallback::callbackObject() const
}
QT_END_NAMESPACE
+
+#include "moc_qquicktimeline_p_p.cpp"
diff --git a/src/quickshapes/qquickshape.cpp b/src/quickshapes/qquickshape.cpp
index 8f2ef3cfc1..f9c0968c7e 100644
--- a/src/quickshapes/qquickshape.cpp
+++ b/src/quickshapes/qquickshape.cpp
@@ -763,6 +763,13 @@ void QQuickShape::setAsynchronous(bool async)
performance. Setting the value to \c true is safe in any case since
rendering falls back to the default method when the vendor-specific
approach, such as \c GL_NV_path_rendering, is not supported at run time.
+
+ \deprecated
+
+ Changing the default value (false) is not recommended. In particular,
+ support for Shape.NvprRenderer will not be available in future Qt versions.
+ Applications experiencing rendering problems with the property set to true
+ are advised to set it to false.
*/
bool QQuickShape::vendorExtensionsEnabled() const
@@ -1515,6 +1522,7 @@ static void generateGradientColorTable(const QQuickShapeGradientCacheKey &gradie
{
int pos = 0;
const QGradientStops &s = gradient.stops;
+ Q_ASSERT(!s.isEmpty());
const bool colorInterpolation = true;
uint alpha = qRound(opacity * 256);
@@ -1552,8 +1560,6 @@ static void generateGradientColorTable(const QQuickShapeGradientCacheKey &gradie
current_color = next_color;
}
- Q_ASSERT(s.size() > 0);
-
uint last_color = ARGB2RGBA(qPremultiply(ARGB_COMBINE_ALPHA(s[sLast].second.rgba(), alpha)));
for ( ; pos < size; ++pos)
colorTable[pos] = last_color;
@@ -1588,7 +1594,10 @@ QSGTexture *QQuickShapeGradientCache::get(const QQuickShapeGradientCacheKey &gra
if (!tx) {
static const int W = 1024; // texture size is 1024x1
QImage gradTab(W, 1, QImage::Format_RGBA8888_Premultiplied);
- generateGradientColorTable(grad, reinterpret_cast<uint *>(gradTab.bits()), W, 1.0f);
+ if (!grad.stops.isEmpty())
+ generateGradientColorTable(grad, reinterpret_cast<uint *>(gradTab.bits()), W, 1.0f);
+ else
+ gradTab.fill(Qt::black);
tx = new QSGPlainTexture;
tx->setImage(gradTab);
switch (grad.spread) {
diff --git a/src/quickshapes/qquickshapegenericrenderer.cpp b/src/quickshapes/qquickshapegenericrenderer.cpp
index 289dee1081..98170be6d9 100644
--- a/src/quickshapes/qquickshapegenericrenderer.cpp
+++ b/src/quickshapes/qquickshapegenericrenderer.cpp
@@ -188,8 +188,12 @@ void QQuickShapeGenericRenderer::setPath(int index, const QQuickPath *path)
void QQuickShapeGenericRenderer::setStrokeColor(int index, const QColor &color)
{
ShapePathData &d(m_sp[index]);
+ const bool wasTransparent = d.strokeColor.a == 0;
d.strokeColor = colorToColor4ub(color);
+ const bool isTransparent = d.strokeColor.a == 0;
d.syncDirty |= DirtyColor;
+ if (wasTransparent && !isTransparent)
+ d.syncDirty |= DirtyStrokeGeom;
}
void QQuickShapeGenericRenderer::setStrokeWidth(int index, qreal w)
@@ -1280,3 +1284,5 @@ QSGMaterialShader *QQuickShapeConicalGradientMaterial::createShader() const
}
QT_END_NAMESPACE
+
+#include "moc_qquickshapegenericrenderer_p.cpp"
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index 39780f8de3..cf021d9a7c 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -978,11 +978,14 @@ void QQuickWidget::createFramebufferObject()
}
QOpenGLContext *shareWindowContext = QWidgetPrivate::get(window())->shareContext();
+ bool nativeContextGotRecreated = false;
if (shareWindowContext && context->shareContext() != shareWindowContext && !qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts)) {
+ d->invalidateRenderControl();
context->setShareContext(shareWindowContext);
context->setScreen(shareWindowContext->screen());
if (!context->create())
qWarning("QQuickWidget: Failed to recreate context");
+ nativeContextGotRecreated = true;
// The screen may be different so we must recreate the offscreen surface too.
// Unlike QOpenGLContext, QOffscreenSurface's create() does not recreate so have to destroy() first.
d->offscreenSurface->destroy();
@@ -1042,6 +1045,10 @@ void QQuickWidget::createFramebufferObject()
// Having one would mean create() was called and platforms that only support
// a single native window were in trouble.
Q_ASSERT(!d->offscreenWindow->handle());
+
+ // do this at the end it may trigger a recursive call
+ if (nativeContextGotRecreated)
+ d->renderControl->initialize(context);
#endif
}
diff --git a/tests/auto/cmake/qtquickcompiler/main.cpp b/tests/auto/cmake/qtquickcompiler/main.cpp
index c357ef60e6..680f81755d 100644
--- a/tests/auto/cmake/qtquickcompiler/main.cpp
+++ b/tests/auto/cmake/qtquickcompiler/main.cpp
@@ -13,7 +13,7 @@ private slots:
void tst_QQC::packaging()
{
QVERIFY(QFile::exists(":/main.qml"));
- QCOMPARE(QFileInfo(":/main.qml").size(), 0);
+ QVERIFY(QFileInfo(":/main.qml").size() > 0);
QVERIFY(QFile::exists(":/main.cpp"));
QVERIFY(QFileInfo(":/main.cpp").size() > 0);
diff --git a/tests/auto/qml/animation/qparallelanimationgroupjob/BLACKLIST b/tests/auto/qml/animation/qparallelanimationgroupjob/BLACKLIST
new file mode 100644
index 0000000000..3793debebb
--- /dev/null
+++ b/tests/auto/qml/animation/qparallelanimationgroupjob/BLACKLIST
@@ -0,0 +1,3 @@
+# See qtbase/src/testlib/qtestblacklist.cpp for format
+[deleteChildrenWithRunningGroup]
+ci macos # QTBUG-106356
diff --git a/tests/auto/qml/animation/qpauseanimationjob/BLACKLIST b/tests/auto/qml/animation/qpauseanimationjob/BLACKLIST
new file mode 100644
index 0000000000..33799b6528
--- /dev/null
+++ b/tests/auto/qml/animation/qpauseanimationjob/BLACKLIST
@@ -0,0 +1,3 @@
+[multipleSequentialGroups]
+macos ci
+
diff --git a/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp b/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp
index 9fe2de5368..2b6145030b 100644
--- a/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp
+++ b/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp
@@ -393,9 +393,7 @@ void Test262Runner::loadTestExpectations()
return;
}
- int line = 0;
while (!file.atEnd()) {
- ++line;
QByteArray line = file.readLine().trimmed();
if (line.startsWith('#') || line.isEmpty())
continue;
@@ -440,9 +438,7 @@ void Test262Runner::updateTestExpectations()
QTemporaryFile updatedExpectations;
updatedExpectations.open();
- int line = 0;
while (!file.atEnd()) {
- ++line;
QByteArray originalLine = file.readLine();
QByteArray line = originalLine.trimmed();
if (line.startsWith('#') || line.isEmpty()) {
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index 3b7d74df63..f1c34e6142 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -102,6 +102,7 @@ private slots:
void valueConversion_RegularExpression();
void castWithMultipleInheritance();
void collectGarbage();
+ void collectGarbageNestedWrappersTwoEngines();
void gcWithNestedDataStructure();
void stacktrace();
void numberParsing_data();
@@ -259,6 +260,7 @@ private slots:
void sortNonStringArray();
void iterateInvalidProxy();
void applyOnHugeArray();
+ void reflectApplyOnHugeArray();
void tostringRecursionCheck();
void arrayIncludesWithLargeArray();
@@ -267,6 +269,9 @@ private slots:
void dataViewCtor();
void uiLanguage();
+ void forOfAndGc();
+
+ void spreadNoOverflow();
public:
Q_INVOKABLE QJSValue throwingCppMethod1();
@@ -1809,6 +1814,44 @@ void tst_QJSEngine::collectGarbage()
QVERIFY(ptr.isNull());
}
+class TestObjectContainer : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject *dummy MEMBER m_dummy CONSTANT)
+
+public:
+ TestObjectContainer() : m_dummy(new QObject(this)) {}
+
+private:
+ QObject *m_dummy;
+};
+
+void tst_QJSEngine::collectGarbageNestedWrappersTwoEngines()
+{
+ QJSEngine engine1;
+ QJSEngine engine2;
+
+ TestObjectContainer container;
+ QQmlEngine::setObjectOwnership(&container, QQmlEngine::CppOwnership);
+
+ engine1.globalObject().setProperty("foobar", engine1.newQObject(&container));
+ engine2.globalObject().setProperty("foobar", engine2.newQObject(&container));
+
+ engine1.evaluate("foobar.dummy.baz = 42");
+ engine2.evaluate("foobar.dummy.baz = 43");
+
+ QCOMPARE(engine1.evaluate("foobar.dummy.baz").toInt(), 42);
+ QCOMPARE(engine2.evaluate("foobar.dummy.baz").toInt(), 43);
+
+ engine1.collectGarbage();
+ engine2.collectGarbage();
+
+ // The GC should not collect dummy object wrappers neither in engine1 nor engine2, we
+ // verify that by checking whether the baz property still has its previous value.
+ QCOMPARE(engine1.evaluate("foobar.dummy.baz").toInt(), 42);
+ QCOMPARE(engine2.evaluate("foobar.dummy.baz").toInt(), 43);
+}
+
void tst_QJSEngine::gcWithNestedDataStructure()
{
// The GC must be able to traverse deeply nested objects, otherwise this
@@ -5134,6 +5177,22 @@ void tst_QJSEngine::applyOnHugeArray()
QCOMPARE(value.toString(), "RangeError: Array too large for apply().");
}
+
+void tst_QJSEngine::reflectApplyOnHugeArray()
+{
+ QQmlEngine engine;
+ const QJSValue value = engine.evaluate(R"(
+(function(){
+const v1 = [];
+const v3 = [];
+v3.length = 3900000000;
+Reflect.apply(v1.reverse,v1,v3);
+})()
+ )");
+ QVERIFY(value.isError());
+ QCOMPARE(value.toString(), QLatin1String("RangeError: Invalid array length."));
+}
+
void tst_QJSEngine::typedArraySet()
{
QJSEngine engine;
@@ -5211,6 +5270,87 @@ void tst_QJSEngine::uiLanguage()
}
}
+void tst_QJSEngine::forOfAndGc()
+{
+ // We want to guard against the iterator of a for..of loop leaving the result unprotected from
+ // garbage collection. It should be possible to construct a pure JS test case, but due to the
+ // vaguaries of garbage collection it's hard to reliably trigger the crash. This test is the
+ // best I could come up with.
+
+ QQmlEngine engine;
+ QQmlComponent c(&engine);
+ c.setData(R"(
+ import QtQml 2.15
+ import QtQml.Models 2.15
+
+ QtObject {
+ id: counter
+ property int count: 0
+
+ property DelegateModel model: DelegateModel {
+ id: filesModel
+
+ model: ListModel {
+ Component.onCompleted: {
+ for (let idx = 0; idx < 50; idx++)
+ append({"i" : idx})
+ }
+ }
+
+ groups: [
+ DelegateModelGroup {
+ name: "selected"
+ }
+ ]
+
+ function getSelected() {
+ for (let i = 0; i < items.count; ++i) {
+ var item = items.get(i)
+ for (let el of item.groups) {
+ if (el === "selected")
+ ++counter.count
+ }
+ }
+ }
+
+ property bool bSelect: true
+ function selectAll() {
+ for (let i = 0; i < items.count; ++i) {
+ if (bSelect && !items.get(i).inSelected)
+ items.addGroups(i, 1, ["selected"])
+ else
+ items.removeGroups(i, 1, ["selected"])
+ getSelected()
+ }
+ bSelect = !bSelect
+ }
+ }
+
+ property Timer timer: Timer {
+ running: true
+ interval: 1
+ repeat: true
+ onTriggered: filesModel.selectAll()
+ }
+ }
+ )", QUrl());
+
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+
+ QTRY_VERIFY(o->property("count").toInt() > 32768);
+}
+
+void tst_QJSEngine::spreadNoOverflow()
+{
+ QJSEngine engine;
+
+ const QString program = QString::fromLatin1("var a = [] ;a.length = 555840;Math.max(...a)");
+ const QJSValue result = engine.evaluate(program);
+ QVERIFY(result.isError());
+ QCOMPARE(result.errorType(), QJSValue::RangeError);
+}
+
QTEST_MAIN(tst_QJSEngine)
#include "tst_qjsengine.moc"
diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
index 3c59f7bd56..773b826e62 100644
--- a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
+++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
@@ -346,7 +346,7 @@ void tst_qmldiskcache::regenerateAfterChange()
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(0);
QCOMPARE(quint32(obj->nBindings), quint32(1));
- QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Script));
+ QCOMPARE(obj->bindingTable()->type(), QV4::CompiledData::Binding::Type_Script);
QCOMPARE(quint32(obj->bindingTable()->value.compiledScriptIndex), quint32(0));
QCOMPARE(quint32(testUnit->functionTableSize), quint32(1));
@@ -374,7 +374,7 @@ void tst_qmldiskcache::regenerateAfterChange()
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(0);
QCOMPARE(quint32(obj->nBindings), quint32(2));
- QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Number));
+ QCOMPARE(obj->bindingTable()->type(), QV4::CompiledData::Binding::Type_Number);
QCOMPARE(reinterpret_cast<const QV4::Value *>(testUnit->constants())
[obj->bindingTable()->value.constantValueIndex].doubleValue(),
@@ -419,7 +419,7 @@ void tst_qmldiskcache::registerImportForImplicitComponent()
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(0);
QCOMPARE(quint32(obj->nBindings), quint32(1));
- QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Object));
+ QCOMPARE(obj->bindingTable()->type(), QV4::CompiledData::Binding::Type_Object);
const QV4::CompiledData::Object *implicitComponent = qmlUnit->objectAt(obj->bindingTable()->value.objectIndex);
QCOMPARE(testUnit->stringAtInternal(implicitComponent->inheritedTypeNameIndex), QStringLiteral("QmlInternals.") + componentType.elementName());
diff --git a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp
index 2610402455..b3e6ffd79e 100644
--- a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp
+++ b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp
@@ -358,9 +358,8 @@ void tst_qqmlbinding::delayed()
// doesn't update immediately
QCOMPARE(item->property("changeCount").toInt(), 1);
- QCoreApplication::processEvents();
// only updates once (non-delayed would update twice)
- QCOMPARE(item->property("changeCount").toInt(), 2);
+ QTRY_COMPARE(item->property("changeCount").toInt(), 2);
}
void tst_qqmlbinding::bindingOverwriting()
diff --git a/tests/auto/qml/qqmlconsole/data/assert.qml b/tests/auto/qml/qqmlconsole/data/assert.qml
index dd580e2a72..9687437c48 100644
--- a/tests/auto/qml/qqmlconsole/data/assert.qml
+++ b/tests/auto/qml/qqmlconsole/data/assert.qml
@@ -29,21 +29,22 @@
import QtQuick 2.0
QtObject {
- property int q:1
+ property int q: 1
+
function assertFail() {
- console.assert(0, "This will fail too")
+ console.assert(0, "This will fail too");
}
Component.onCompleted: {
- var x = 12;
+ const x = 12;
console.assert(x == 12, "This will pass");
try {
- console.assert(x < 12, "This will fail");
+ console.assert(x < 12, "This will fail");
} catch (e) {
console.log(e);
}
- console.assert("x < 12", "This will pass too")
+ console.assert("x < 12", "This will pass too");
assertFail();
- console.assert(1)
+ console.assert(1);
}
}
diff --git a/tests/auto/qml/qqmlconsole/data/categorized_logging.qml b/tests/auto/qml/qqmlconsole/data/categorized_logging.qml
index d593f0dfa1..6d471e7f80 100644
--- a/tests/auto/qml/qqmlconsole/data/categorized_logging.qml
+++ b/tests/auto/qml/qqmlconsole/data/categorized_logging.qml
@@ -40,7 +40,7 @@
import QtQuick 2.12
Item {
- id:root
+ id: root
LoggingCategory {
id: testCategory
@@ -69,8 +69,11 @@ Item {
console.warn(testCategoryStartingFromWarning, "console.warn");
console.error(testCategoryStartingFromWarning, "console.error");
- testCategory.name = "qt.test2";
- testCategory.defaultLogLevel = LoggingCategory.Debug;
+ testCategory.name = "qt.test"; // should be silent
+ testCategoryStartingFromWarning.name = "qt.test.other"; // should issue a warning
+
+ testCategory.defaultLogLevel = LoggingCategory.Debug; // should be silent
+ testCategoryStartingFromWarning.defaultLogLevel = LoggingCategory.Debug; // should issue a warning
console.error(emptyCategory, "console.error");
}
diff --git a/tests/auto/qml/qqmlconsole/data/exception.qml b/tests/auto/qml/qqmlconsole/data/exception.qml
index 63afd18828..b9b83525e8 100644
--- a/tests/auto/qml/qqmlconsole/data/exception.qml
+++ b/tests/auto/qml/qqmlconsole/data/exception.qml
@@ -30,12 +30,12 @@ import QtQuick 2.0
QtObject {
function exceptionFail() {
- console.exception("Exception 2")
+ console.exception("Exception 2");
}
Component.onCompleted: {
try {
- console.exception("Exception 1")
+ console.exception("Exception 1");
} catch (e) {
console.log(e);
}
diff --git a/tests/auto/qml/qqmlconsole/data/logging.qml b/tests/auto/qml/qqmlconsole/data/logging.qml
index f5eaeb442a..ac3884bc8e 100644
--- a/tests/auto/qml/qqmlconsole/data/logging.qml
+++ b/tests/auto/qml/qqmlconsole/data/logging.qml
@@ -30,7 +30,8 @@
import QtQuick 2.0
QtObject {
- id:root
+ id: root
+
required property var customObject
required property var stringListProperty
@@ -49,14 +50,14 @@ QtObject {
consoleCount();
consoleCount();
- var a = [1, 2];
- var b = {a: "hello", d: 1 };
- b.toString = function() { return JSON.stringify(b) }
- var c
- var d = 12;
- var e = function() { return 5;};
- var f = true;
- var g = {toString: function() { throw new Error('toString'); }};
+ const a = [1, 2];
+ const b = { a: "hello", d: 1 };
+ b.toString = function() { return JSON.stringify(b); }
+ let c;
+ const d = 12;
+ const e = function() { return 5; };
+ const f = true;
+ const g = { toString: function() { throw new Error('toString'); } };
console.log(a);
console.log(b);
@@ -79,6 +80,6 @@ QtObject {
return;
}
- throw ("console.log(exception) should have raised an exception");
+ throw "console.log(exception) should have raised an exception";
}
}
diff --git a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp
index 48613d04f1..3a25dfb10d 100644
--- a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp
+++ b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp
@@ -134,18 +134,27 @@ void tst_qqmlconsole::categorized_logging()
QVERIFY(messageHandler.messages().contains("qt.test.warning: console.error"));
QString emptyCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(56).arg(5) +
- "QML LoggingCategory: Declaring the name of the LoggingCategory is mandatory and cannot be changed later !";
+ "QML LoggingCategory: Declaring the name of a LoggingCategory is mandatory and cannot be changed later";
QVERIFY(messageHandler.messages().contains(emptyCategory));
- QString changedCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(45).arg(5) +
- "QML LoggingCategory: The name of a LoggingCategory cannot be changed after the Item is created";
+
+ QString notChangedCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(45).arg(5) +
+ "QML LoggingCategory: The name of a LoggingCategory cannot be changed after the component is completed";
+ QVERIFY(!messageHandler.messages().contains(notChangedCategory));
+ QString changedCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(50).arg(5) +
+ "QML LoggingCategory: The name of a LoggingCategory cannot be changed after the component is completed";
QVERIFY(messageHandler.messages().contains(changedCategory));
- QString changedDefaultLogLevel = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(45).arg(5) +
- "QML LoggingCategory: The defaultLogLevel of a LoggingCategory cannot be changed after the Item is created";
+
+ QString notChangedDefaultLogLevel = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(45).arg(5) +
+ "QML LoggingCategory: The defaultLogLevel of a LoggingCategory cannot be changed after the component is completed";
+ QVERIFY(!messageHandler.messages().contains(notChangedDefaultLogLevel));
+ QString changedDefaultLogLevel = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(50).arg(5) +
+ "QML LoggingCategory: The defaultLogLevel of a LoggingCategory cannot be changed after the component is completed";
QVERIFY(messageHandler.messages().contains(changedDefaultLogLevel));
- QString useEmptyCategory = "default: " + QString::fromLatin1("%1:%2: ").arg(testUrl.toString()).arg(75) +
+
+ QString useEmptyCategory = "default: " + QString::fromLatin1("%1:%2: ").arg(testUrl.toString()).arg(78) +
"Error: A QmlLoggingCatgory was provided without a valid name";
QVERIFY(messageHandler.messages().contains(useEmptyCategory));
@@ -188,11 +197,11 @@ void tst_qqmlconsole::testAssert()
// assert()
QString assert1 = "This will fail\n" +
- QString::fromLatin1("onCompleted (%1:%2)").arg(testUrl.toString()).arg(41);
+ QString::fromLatin1("onCompleted (%1:%2)").arg(testUrl.toString()).arg(42);
QString assert2 = "This will fail too\n" +
- QString::fromLatin1("assertFail (%1:%2)\n").arg(testUrl.toString()).arg(34) +
- QString::fromLatin1("onCompleted (%1:%2)").arg(testUrl.toString()).arg(46);
+ QString::fromLatin1("assertFail (%1:%2)\n").arg(testUrl.toString()).arg(35) +
+ QString::fromLatin1("onCompleted (%1:%2)").arg(testUrl.toString()).arg(47);
QTest::ignoreMessage(QtCriticalMsg, qPrintable(assert1));
QTest::ignoreMessage(QtCriticalMsg, qPrintable(assert2));
diff --git a/tests/auto/qml/qqmlecmascript/data/functionAsDefaultArgument.qml b/tests/auto/qml/qqmlecmascript/data/functionAsDefaultArgument.qml
new file mode 100644
index 0000000000..9f576d1af8
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/functionAsDefaultArgument.qml
@@ -0,0 +1,8 @@
+import QtQml 2.15
+
+QtObject {
+ id: root
+
+ function f(inner=function(){ root.objectName = "didRun" } ){ inner() }
+ Component.onCompleted: f()
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.js b/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.js
new file mode 100644
index 0000000000..f51ab662ab
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.js
@@ -0,0 +1,29 @@
+function init() {
+ Array.prototype.doPush = Array.prototype.push
+}
+
+function nasty() {
+ var sc_Vector = Array;
+ var push = sc_Vector.prototype.doPush;
+
+ // Change the memberData to hold something nasty on the current internalClass
+ sc_Vector.prototype.doPush = 5;
+
+ // Trigger a re-allocation of memberData
+ for (var i = 0; i < 256; ++i)
+ sc_Vector.prototype[i + "string"] = function() { return 98; }
+
+ // Change the (new) memberData back, to hold our doPush function again.
+ // This should propagate a protoId change all the way up to the lookup.
+ sc_Vector.prototype.doPush = push;
+}
+
+function func() {
+ var b = [];
+
+ // This becomes a lookup internally, which stores protoId and a pointer
+ // into the memberData. It should get invalidated when memberData is re-allocated.
+ b.doPush(3);
+
+ return b;
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.qml b/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.qml
new file mode 100644
index 0000000000..460c40a750
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.qml
@@ -0,0 +1,13 @@
+import QtQml 2.15
+
+import "internalClassParentGc.js" as Foo
+
+QtObject {
+ Component.onCompleted: {
+ gc();
+ Foo.init();
+ Foo.func();
+ Foo.nasty();
+ objectName = Foo.func()[0];
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 7da1b2c500..9d5ffda180 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -241,6 +241,7 @@ private slots:
void topLevelGeneratorFunction();
void generatorCrashNewProperty();
void generatorCallsGC();
+ void noYieldInInnerFunction();
void qtbug_10696();
void qtbug_11606();
void qtbug_11600();
@@ -387,6 +388,9 @@ private slots:
void proxyIteration();
void proxyHandlerTraps();
void gcCrashRegressionTest();
+ void functionAsDefaultArgument();
+
+ void internalClassParentGc();
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
@@ -6515,6 +6519,19 @@ void tst_qqmlecmascript::generatorCallsGC()
QVERIFY2(o != nullptr, qPrintable(component.errorString()));
}
+void tst_qqmlecmascript::noYieldInInnerFunction()
+{
+ QJSEngine engine;
+ const QString program = R"(
+ function *a() {
+ (function() { yield 1; })();
+ };
+ )";
+ auto result = engine.evaluate(program);
+ QVERIFY(result.isError());
+ QCOMPARE(result.errorType(), QJSValue::SyntaxError);
+}
+
// Test the "Qt.include" method
void tst_qqmlecmascript::include()
{
@@ -9371,6 +9388,24 @@ void tst_qqmlecmascript::proxyHandlerTraps()
QVERIFY(value.isString() && value.toString() == QStringLiteral("SUCCESS"));
}
+void tst_qqmlecmascript::functionAsDefaultArgument()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("functionAsDefaultArgument.qml"));
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY(root);
+ QCOMPARE(root->objectName(), "didRun");
+}
+
+void tst_qqmlecmascript::internalClassParentGc()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("internalClassParentGc.qml"));
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY(root);
+ QCOMPARE(root->objectName(), "3");
+}
+
QTEST_MAIN(tst_qqmlecmascript)
#include "tst_qqmlecmascript.moc"
diff --git a/tests/auto/qml/qqmlinstantiator/data/activeModelChangeInteraction.qml b/tests/auto/qml/qqmlinstantiator/data/activeModelChangeInteraction.qml
new file mode 100644
index 0000000000..2797566ad2
--- /dev/null
+++ b/tests/auto/qml/qqmlinstantiator/data/activeModelChangeInteraction.qml
@@ -0,0 +1,39 @@
+import QtQuick 2.15
+import QtQml.Models 2.15
+
+Item {
+ id: root
+ property int instanceCount: 0
+ property alias active: instantiator.active
+
+ ListModel {
+ id: listmodel
+
+ dynamicRoles: true
+ }
+
+ Component.onCompleted: {
+ listmodel.insert(listmodel.count, {name: "one"})
+ listmodel.insert(listmodel.count, {name: "two"})
+ listmodel.insert(listmodel.count, {name: "three"})
+ }
+
+ Instantiator {
+ id: instantiator
+
+ active: false
+
+ model: listmodel
+
+ delegate: Text {
+ width: 100
+ height: 20
+
+ text: name
+
+ Component.onCompleted: ++root.instanceCount
+ }
+
+ }
+}
+
diff --git a/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp b/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp
index 84e08c471a..d5587432de 100644
--- a/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp
+++ b/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp
@@ -47,6 +47,7 @@ private slots:
void createMultiple();
void stringModel();
void activeProperty();
+ void activeModelChangeInteraction();
void intModelChange();
void createAndRemove();
@@ -153,6 +154,26 @@ void tst_qqmlinstantiator::activeProperty()
QCOMPARE(object->property("idx").toInt(), 0);
}
+void tst_qqmlinstantiator::activeModelChangeInteraction()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("activeModelChangeInteraction.qml"));
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY(root);
+
+ // If the instantiator is inactive, a model change does not lead to items being loaded
+ bool ok = false;
+ int count = root->property("instanceCount").toInt(&ok);
+ QVERIFY(ok);
+ QCOMPARE(count, 0);
+
+ // When turning the instantiator active, it will however reflect the model
+ root->setProperty("active", true);
+ count = root->property("instanceCount").toInt(&ok);
+ QVERIFY(ok);
+ QCOMPARE(count, 3);
+}
+
void tst_qqmlinstantiator::intModelChange()
{
QQmlEngine engine;
diff --git a/tests/auto/qml/qqmllanguage/data/Broken.qml b/tests/auto/qml/qqmllanguage/data/Broken.qml
new file mode 100644
index 0000000000..e1b61f31f4
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/Broken.qml
@@ -0,0 +1,5 @@
+import QtQml
+
+QtObject {
+ notThere: 5
+}
diff --git a/tests/auto/qml/qqmllanguage/data/ComponentType.qml b/tests/auto/qml/qqmllanguage/data/ComponentType.qml
new file mode 100644
index 0000000000..ad0dad455c
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/ComponentType.qml
@@ -0,0 +1,8 @@
+import QtQml 2
+
+Component {
+ id: componentRoot
+ QtObject {
+ objectName: "enclosed"
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/alias.15a.qml b/tests/auto/qml/qqmllanguage/data/alias.15a.qml
new file mode 100644
index 0000000000..b5f96e15c1
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/alias.15a.qml
@@ -0,0 +1,33 @@
+import QtQuick 2.15
+
+Item {
+ id: root
+
+ property alias symbol: symbol
+ symbol.layer.enabled: true
+
+ Item {
+ id: symbol
+ }
+
+ Rectangle {
+ id: txtElevationValue
+
+ property Rectangle background: Rectangle { }
+
+ state: "ValidatorInvalid"
+
+ states: [
+ State {
+ name: "ValidatorInvalid"
+ PropertyChanges {
+ target: txtElevationValue
+ background.border.color: "red" // this line caused the segfault in qtbug107795
+ }
+ },
+ State {
+ name: "ValidatorAcceptable"
+ }
+ ]
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/ambiguousBinding/TestCase.qml b/tests/auto/qml/qqmllanguage/data/ambiguousBinding/TestCase.qml
new file mode 100644
index 0000000000..c76d2b679e
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/ambiguousBinding/TestCase.qml
@@ -0,0 +1,6 @@
+import QtQml 2.15
+import QtTest 1.0
+
+QtObject {
+ component Comp: QtObject {}
+}
diff --git a/tests/auto/qml/qqmllanguage/data/ambiguousBinding/ambiguousContainingType.qml b/tests/auto/qml/qqmllanguage/data/ambiguousBinding/ambiguousContainingType.qml
new file mode 100644
index 0000000000..765dc91fe1
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/ambiguousBinding/ambiguousContainingType.qml
@@ -0,0 +1,3 @@
+import QtQml 2.15
+
+TestCase {}
diff --git a/tests/auto/qml/qqmllanguage/data/asBroken.qml b/tests/auto/qml/qqmllanguage/data/asBroken.qml
new file mode 100644
index 0000000000..bd88d14c76
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/asBroken.qml
@@ -0,0 +1,6 @@
+import QtQml 2.15
+
+QtObject {
+ id: self
+ property var selfAsBroken: self as Broken
+}
diff --git a/tests/auto/qml/qqmllanguage/data/badGroupedProperty.qml b/tests/auto/qml/qqmllanguage/data/badGroupedProperty.qml
new file mode 100644
index 0000000000..34dcbf96fa
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/badGroupedProperty.qml
@@ -0,0 +1,10 @@
+import QtQml 2.15
+
+QtObject {
+ id: testItem
+ property rect rect
+ onComplete {
+ rect.x: 2
+ rect.width: 22
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl.qml b/tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl.qml
new file mode 100644
index 0000000000..7e10553ae7
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl.qml
@@ -0,0 +1,11 @@
+import QtQuick 2
+
+Item {
+ id: root
+ Component {
+ id: accessibleNormal
+ Item {}
+ }
+ property alias accessibleNormalUrl: accessibleNormal.url
+ property url urlClone: root.accessibleNormalUrl // crashes qml utility
+}
diff --git a/tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl2.qml b/tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl2.qml
new file mode 100644
index 0000000000..899b7aca37
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl2.qml
@@ -0,0 +1,11 @@
+import QtQuick 2
+Item {
+ id: root
+ Component {
+ id: accessibleNormal
+ ComponentType {
+ id: inaccessibleNormal
+ }
+ }
+ property alias accessibleNormalProgress: accessibleNormal.progress
+}
diff --git a/tests/auto/qml/qqmllanguage/data/fuzzed.1.errors.txt b/tests/auto/qml/qqmllanguage/data/fuzzed.1.errors.txt
index e399799fe9..758be7feae 100644
--- a/tests/auto/qml/qqmllanguage/data/fuzzed.1.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/fuzzed.1.errors.txt
@@ -1,2 +1 @@
-2:8:Cannot assign to non-existent property "_G"
-
+2:11:Non-existent attached object
diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp
index 31a4135d89..df9d1401a9 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.cpp
+++ b/tests/auto/qml/qqmllanguage/testtypes.cpp
@@ -174,7 +174,7 @@ void EnumSupportingCustomParser::verifyBindings(const QQmlRefPointer<QV4::Execut
return;
}
- if (binding->type != QV4::CompiledData::Binding::Type_Script) {
+ if (binding->type() != QV4::CompiledData::Binding::Type_Script) {
error(binding, QStringLiteral("Custom parser invoked with the wrong property value. Expected script that evaluates to enum"));
return;
}
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 31bf30c57c..92d0069ce4 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -28,6 +28,7 @@
#include <qtest.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlprivate.h>
#include <QtQml/qqmlincubator.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qfile.h>
@@ -337,6 +338,13 @@ private slots:
void hangOnWarning();
+ void ambiguousContainingType();
+ void staticConstexprMembers();
+ void bindingAliasToComponentUrl();
+ void badGroupedProperty();
+
+ void objectAsBroken();
+
private:
QQmlEngine engine;
QStringList defaultImportPathList;
@@ -2144,6 +2152,22 @@ void tst_qqmllanguage::aliasProperties()
QCOMPARE(subItem->property("y").toInt(), 1);
}
+ // Nested property bindings on group properties that are actually aliases (QTBUG-94983)
+ {
+ QQmlComponent component(&engine, testFileUrl("alias.15a.qml"));
+ VERIFY_ERRORS(0);
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QPointer<QObject> subItem = qvariant_cast<QObject*>(object->property("symbol"));
+ QVERIFY(!subItem.isNull());
+
+ QPointer<QObject> subSubItem = qvariant_cast<QObject*>(subItem->property("layer"));
+
+ QCOMPARE(subSubItem->property("enabled").value<bool>(), true);
+ }
+
// Alias to sub-object with binding (QTBUG-57041)
{
// This is shold *not* crash.
@@ -5860,6 +5884,93 @@ void tst_qqmllanguage::hangOnWarning()
QVERIFY(object != nullptr);
}
+void tst_qqmllanguage::ambiguousContainingType()
+{
+ // Need to do it twice, so that we load from disk cache the second time.
+ for (int i = 0; i < 2; ++i) {
+ QQmlEngine engine;
+
+ // Should not crash when loading the type
+ QQmlComponent c(&engine, testFileUrl("ambiguousBinding/ambiguousContainingType.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+ }
+}
+ void tst_qqmllanguage::staticConstexprMembers() {
+ // this tests if the symbols are correclty defined for c++11 (gcc 11 and 12), and should
+ // not have any linker errors
+ using T = QObject;
+ using T2 = QObject;
+
+ auto f1 = QQmlPrivate::Constructors<T, true>::createSingletonInstance;
+ auto f2 = QQmlPrivate::Constructors<T, false>::createSingletonInstance;
+ auto f3 = QQmlPrivate::Constructors<T, true>::createInto;
+
+ auto f4 = QQmlPrivate::ExtendedType<T, true>::createParent;
+ auto f5 = QQmlPrivate::ExtendedType<T, false>::createParent;
+ auto f6 = QQmlPrivate::ExtendedType<T, true>::staticMetaObject;
+
+ auto f7 = QQmlPrivate::QmlSingleton<T, T2>::Value;
+
+ Q_UNUSED(f1);
+ Q_UNUSED(f2);
+ Q_UNUSED(f3);
+ Q_UNUSED(f3);
+ Q_UNUSED(f4);
+ Q_UNUSED(f5);
+ Q_UNUSED(f6);
+ Q_UNUSED(f7);
+ }
+
+void tst_qqmllanguage::bindingAliasToComponentUrl()
+{
+ QQmlEngine engine;
+ {
+ QQmlComponent component(&engine, testFileUrl("bindingAliasToComponentUrl.qml"));
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object);
+ QCOMPARE(object->property("accessibleNormalUrl"), object->property("urlClone"));
+ }
+ {
+ QQmlComponent component(&engine, testFileUrl("bindingAliasToComponentUrl2.qml"));
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object);
+ QCOMPARE(object->property("accessibleNormalProgress"), QVariant(1.0));
+ }
+}
+
+void tst_qqmllanguage::badGroupedProperty()
+{
+ QQmlEngine engine;
+ const QUrl url = testFileUrl("badGroupedProperty.qml");
+ QQmlComponent c(&engine, url);
+ QVERIFY(c.isError());
+ QCOMPARE(c.errorString(),
+ QStringLiteral("%1:6 Cannot assign to non-existent property \"onComplete\"\n")
+ .arg(url.toString()));
+}
+
+void tst_qqmllanguage::objectAsBroken()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("asBroken.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+ QVariant selfAsBroken = o->property("selfAsBroken");
+ QVERIFY(selfAsBroken.isValid());
+
+ // 5.15 doesn't enforce type annotation. So the "as" cast succeeds even though
+ // the target type cannot be resolved.
+ QCOMPARE(selfAsBroken.value<QObject *>(), o.data());
+
+ QQmlComponent b(&engine, testFileUrl("Broken.qml"));
+ QVERIFY(b.isError());
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"
diff --git a/tests/auto/qml/qqmllistcompositor/tst_qqmllistcompositor.cpp b/tests/auto/qml/qqmllistcompositor/tst_qqmllistcompositor.cpp
index b49832499e..9315b2d24d 100644
--- a/tests/auto/qml/qqmllistcompositor/tst_qqmllistcompositor.cpp
+++ b/tests/auto/qml/qqmllistcompositor/tst_qqmllistcompositor.cpp
@@ -89,15 +89,13 @@ QT_END_NAMESPACE
static const C::Group Visible = C::Group(2);
static const C::Group Selection = C::Group(3);
+constexpr auto VisibleFlag = C::Flag(0x04);
+constexpr auto SelectionFlag = C::Flag(0x08);
+
class tst_qqmllistcompositor : public QObject
{
Q_OBJECT
- enum {
- VisibleFlag = 0x04,
- SelectionFlag = 0x08
- };
-
void populateChange(
C::Change &change, int sIndex, int vIndex, int dIndex, int cIndex, int count, int flags, int moveId)
{
diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
index 5363cc8fcb..4032a4448d 100644
--- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
+++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
@@ -1943,7 +1943,8 @@ void tst_qqmlproperty::copy()
{
PropertyObject object;
- QQmlProperty *property = new QQmlProperty(&object, QLatin1String("defaultProperty"));
+ QScopedPointer<QQmlProperty> property(
+ new QQmlProperty(&object, QLatin1String("defaultProperty")));
QCOMPARE(property->name(), QString("defaultProperty"));
QCOMPARE(property->read(), QVariant(10));
QCOMPARE(property->type(), QQmlProperty::Property);
@@ -1966,7 +1967,7 @@ void tst_qqmlproperty::copy()
QCOMPARE(p2.propertyTypeCategory(), QQmlProperty::Normal);
QCOMPARE(p2.propertyType(), (int)QVariant::Int);
- delete property; property = nullptr;
+ property.reset();
QCOMPARE(p1.name(), QString("defaultProperty"));
QCOMPARE(p1.read(), QVariant(10));
@@ -1979,6 +1980,16 @@ void tst_qqmlproperty::copy()
QCOMPARE(p2.type(), QQmlProperty::Property);
QCOMPARE(p2.propertyTypeCategory(), QQmlProperty::Normal);
QCOMPARE(p2.propertyType(), (int)QVariant::Int);
+
+ p1 = QQmlProperty();
+ QQmlPropertyPrivate *p2d = QQmlPropertyPrivate::get(p2);
+ QCOMPARE(p2d->count(), 1);
+
+ // Use a pointer to avoid compiler warning about self-assignment.
+ QQmlProperty *p2p = &p2;
+ *p2p = p2;
+
+ QCOMPARE(p2d->count(), 1);
}
void tst_qqmlproperty::noContext()
diff --git a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
index a75a00bd01..b6e0b00cc4 100644
--- a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
+++ b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
@@ -96,13 +96,13 @@ void tst_qqmltranslation::translation()
const bool expectCompiledTranslation = compiledTranslations.contains(propertyName);
if (expectCompiledTranslation) {
- if (binding->type != QV4::CompiledData::Binding::Type_Translation)
+ if (binding->type() != QV4::CompiledData::Binding::Type_Translation)
qDebug() << "binding for property" << propertyName << "is not a compiled translation";
- QCOMPARE(quint32(binding->type), quint32(QV4::CompiledData::Binding::Type_Translation));
+ QCOMPARE(binding->type(), QV4::CompiledData::Binding::Type_Translation);
} else {
- if (binding->type == QV4::CompiledData::Binding::Type_Translation)
+ if (binding->type() == QV4::CompiledData::Binding::Type_Translation)
qDebug() << "binding for property" << propertyName << "is not supposed to be a compiled translation";
- QVERIFY(binding->type != QV4::CompiledData::Binding::Type_Translation);
+ QVERIFY(binding->type() != QV4::CompiledData::Binding::Type_Translation);
}
}
}
@@ -148,11 +148,11 @@ void tst_qqmltranslation::idTranslation()
for (quint32 i = 0; i < rootObject->nBindings; ++i, ++binding) {
const QString propertyName = compilationUnit->stringAt(binding->propertyNameIndex);
if (propertyName == "idTranslation") {
- if (binding->type != QV4::CompiledData::Binding::Type_TranslationById)
+ if (binding->type() != QV4::CompiledData::Binding::Type_TranslationById)
qDebug() << "binding for property" << propertyName << "is not a compiled translation";
- QCOMPARE(quint32(binding->type), quint32(QV4::CompiledData::Binding::Type_TranslationById));
+ QCOMPARE(binding->type(), QV4::CompiledData::Binding::Type_TranslationById);
} else {
- QVERIFY(binding->type != QV4::CompiledData::Binding::Type_Translation);
+ QVERIFY(binding->type() != QV4::CompiledData::Binding::Type_Translation);
}
}
}
diff --git a/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp b/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp
index 5dd8e9dcc0..5d9be077fe 100644
--- a/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp
+++ b/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp
@@ -148,6 +148,9 @@ void tst_QV4Assembler::jitEnabled()
#elif defined(Q_OS_WIN) && defined(Q_PROCESSOR_ARM)
/* JIT should be disabled Windows on ARM/ARM64 for now. */
QVERIFY(!QT_CONFIG(qml_jit));
+#elif defined(Q_OS_MACOS) && defined(Q_PROCESSOR_ARM)
+ /* JIT should be disabled on macOS on ARM/ARM64 for now. */
+ QVERIFY(!QT_CONFIG(qml_jit));
#else
/* JIT should be enabled on all other architectures/OSes tested in CI. */
QVERIFY(QT_CONFIG(qml_jit));
diff --git a/tests/auto/qml/qv4mm/tst_qv4mm.cpp b/tests/auto/qml/qv4mm/tst_qv4mm.cpp
index 5d635aa63b..34da3a7c50 100644
--- a/tests/auto/qml/qv4mm/tst_qv4mm.cpp
+++ b/tests/auto/qml/qv4mm/tst_qv4mm.cpp
@@ -47,7 +47,7 @@ private slots:
void gcStats();
void multiWrappedQObjects();
void accessParentOnDestruction();
- void clearICParent();
+ void cleanInternalClasses();
};
void tst_qv4mm::gcStats()
@@ -76,10 +76,10 @@ void tst_qv4mm::multiWrappedQObjects()
QCOMPARE(engine1.memoryManager->m_pendingFreedObjectWrapperValue.size(), 1);
QCOMPARE(engine2.memoryManager->m_pendingFreedObjectWrapperValue.size(), 0);
- // Moves the additional WeakValue from m_multiplyWrappedQObjects to
- // m_pendingFreedObjectWrapperValue. It's still alive after all.
+ // The additional WeakValue from m_multiplyWrappedQObjects hasn't been moved
+ // to m_pendingFreedObjectWrapperValue yet. It's still alive after all.
engine1.memoryManager->runGC();
- QCOMPARE(engine1.memoryManager->m_pendingFreedObjectWrapperValue.size(), 2);
+ QCOMPARE(engine1.memoryManager->m_pendingFreedObjectWrapperValue.size(), 1);
// engine2 doesn't own the object as engine1 was the first to wrap it above.
// Therefore, no effect here.
@@ -110,16 +110,41 @@ void tst_qv4mm::accessParentOnDestruction()
QCOMPARE(obj->property("destructions").toInt(), 100);
}
-void tst_qv4mm::clearICParent()
+void tst_qv4mm::cleanInternalClasses()
{
QV4::ExecutionEngine engine;
QV4::Scope scope(engine.rootContext());
QV4::ScopedObject object(scope, engine.newObject());
+ QV4::ScopedObject prototype(scope, engine.newObject());
+
+ // Set a prototype so that we get a unique IC.
+ object->setPrototypeOf(prototype);
+
+ QV4::Scoped<QV4::InternalClass> prevIC(scope, object->internalClass());
+ QVERIFY(prevIC->d()->transitions.empty());
+
+ uint prevIcChainLength = 0;
+ for (QV4::Heap::InternalClass *ic = object->internalClass(); ic; ic = ic->parent)
+ ++prevIcChainLength;
+
+ const auto checkICCHainLength = [&]() {
+ uint icChainLength = 0;
+ for (QV4::Heap::InternalClass *ic = object->internalClass(); ic; ic = ic->parent)
+ ++icChainLength;
+
+ const uint redundant = object->internalClass()->numRedundantTransitions;
+ QVERIFY(redundant <= QV4::Heap::InternalClass::MaxRedundantTransitions);
+
+ // A removal makes two transitions redundant.
+ QVERIFY(icChainLength <= prevIcChainLength + 2 * redundant);
+ };
+
+ const uint numTransitions = 16 * 1024;
// Keep identifiers in a separate array so that we don't have to allocate them in the loop that
// should test the GC on InternalClass allocations.
QV4::ScopedArrayObject identifiers(scope, engine.newArrayObject());
- for (uint i = 0; i < 16 * 1024; ++i) {
+ for (uint i = 0; i < numTransitions; ++i) {
QV4::Scope scope(&engine);
QV4::ScopedString s(scope);
s = engine.newIdentifier(QString::fromLatin1("key%1").arg(i));
@@ -130,22 +155,60 @@ void tst_qv4mm::clearICParent()
object->insertMember(s, v);
}
- // When allocating the InternalClass objects required for deleting properties, the GC should
- // eventually run and remove all but the last two.
- // If we ever manage to avoid allocating the InternalClasses in the first place we will need
- // to change this test.
- for (uint i = 0; i < 16 * 1024; ++i) {
+ // There is a chain of ICs originating from the original class.
+ QCOMPARE(prevIC->d()->transitions.size(), 1u);
+ QVERIFY(prevIC->d()->transitions.front().lookup != nullptr);
+
+ // When allocating the InternalClass objects required for deleting properties, eventually
+ // the IC chain gets truncated, dropping all the removed properties.
+ for (uint i = 0; i < numTransitions; ++i) {
QV4::Scope scope(&engine);
QV4::ScopedString s(scope, identifiers->get(i));
QV4::Scoped<QV4::InternalClass> ic(scope, object->internalClass());
QVERIFY(ic->d()->parent != nullptr);
- object->deleteProperty(s->toPropertyKey());
+ QV4::ScopedValue val(scope, object->get(s->toPropertyKey()));
+ QCOMPARE(val->toNumber(), double(i));
+ QVERIFY(object->deleteProperty(s->toPropertyKey()));
+ QVERIFY(!object->hasProperty(s->toPropertyKey()));
QVERIFY(object->internalClass() != ic->d());
- QCOMPARE(object->internalClass()->parent, ic->d());
- if (ic->d()->parent == nullptr)
- return;
}
- QFAIL("Garbage collector was not triggered by large amount of InternalClasses");
+
+ // None of the properties we've added are left
+ for (uint i = 0; i < numTransitions; ++i) {
+ QV4::ScopedString s(scope, identifiers->get(i));
+ QVERIFY(!object->hasProperty(s->toPropertyKey()));
+ }
+
+ // Also no other properties have appeared
+ QScopedPointer<QV4::OwnPropertyKeyIterator> iterator(object->ownPropertyKeys(object));
+ QVERIFY(!iterator->next(object).isValid());
+
+ checkICCHainLength();
+
+ // Add and remove properties until it clears all remaining redundant ones
+ uint i = 0;
+ while (object->internalClass()->numRedundantTransitions > 0) {
+ i = (i + 1) % numTransitions;
+ QV4::ScopedString s(scope, identifiers->get(i));
+ QV4::ScopedValue v(scope);
+ v->setDouble(i);
+ object->insertMember(s, v);
+ QVERIFY(object->deleteProperty(s->toPropertyKey()));
+ }
+
+ // Make sure that all dangling ICs are actually gone.
+ scope.engine->memoryManager->runGC();
+
+ // Now the GC has removed the ICs we originally added by adding properties.
+ QVERIFY(prevIC->d()->transitions.empty() || prevIC->d()->transitions.front().lookup == nullptr);
+
+ // Same thing with redundant prototypes
+ for (uint i = 0; i < numTransitions; ++i) {
+ QV4::ScopedObject prototype(scope, engine.newObject());
+ object->setPrototypeOf(prototype); // Makes previous prototype redundant
+ }
+
+ checkICCHainLength();
}
QTEST_MAIN(tst_qv4mm)
diff --git a/tests/auto/qmltest/events/tst_wheel.qml b/tests/auto/qmltest/events/tst_wheel.qml
index 96338a51ec..fc38141971 100644
--- a/tests/auto/qmltest/events/tst_wheel.qml
+++ b/tests/auto/qmltest/events/tst_wheel.qml
@@ -64,7 +64,7 @@ Rectangle {
verify(flick.contentX == 0);
flick.contentY = 0;
verify(flick.contentY == 0);
- mouseWheel(flick, 200, 200, -120, 0, Qt.NoButton, Qt.NoModifier, -1);
+ mouseWheel(flick, 200, 200, -120, 0, Qt.NoButton, Qt.NoModifier, 100);
wait(1000);
verify(flick.contentX > 0);
verify(flick.contentY == 0);
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragMargin.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragMargin.qml
index e5ca681bd5..60ea740105 100644
--- a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragMargin.qml
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragMargin.qml
@@ -1,4 +1,4 @@
-import QtQuick 2.12
+import QtQuick 2.15
Rectangle {
color: "#333"
@@ -13,6 +13,7 @@ Rectangle {
DragHandler {
id: dragHandler
margin: 20
+ cursorShape: Qt.ClosedHandCursor
}
Rectangle {
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
index f71febbaf9..40b138bc70 100644
--- a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
@@ -411,6 +411,9 @@ void tst_DragHandler::dragFromMargin() // QTBUG-74966
QVERIFY(!dragHandler->active());
QCOMPARE(dragHandler->centroid().scenePosition(), scenePressPos);
QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos);
+#if QT_CONFIG(cursor)
+ QCOMPARE(window->cursor().shape(), Qt::ArrowCursor);
+#endif
p1 += QPoint(dragThreshold * 2, 0);
QTest::mouseMove(window, p1);
QTRY_VERIFY(dragHandler->active());
@@ -419,9 +422,18 @@ void tst_DragHandler::dragFromMargin() // QTBUG-74966
QCOMPARE(dragHandler->translation().x(), 0.0); // hmm that's odd
QCOMPARE(dragHandler->translation().y(), 0.0);
QCOMPARE(draggableItem->position(), originalPos + QPointF(dragThreshold * 2, 0));
+#if QT_CONFIG(cursor)
+ // The cursor doesn't change until the next event after the handler becomes active.
+ p1 += QPoint(1, 0);
+ QTest::mouseMove(window, p1);
+ QTRY_COMPARE(window->cursor().shape(), Qt::ClosedHandCursor);
+#endif
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
QTRY_VERIFY(!dragHandler->active());
QCOMPARE(dragHandler->centroid().pressedButtons(), Qt::NoButton);
+#if QT_CONFIG(cursor)
+ QTRY_COMPARE(window->cursor().shape(), Qt::ArrowCursor);
+#endif
}
void tst_DragHandler::snapMode_data()
diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/windowCursorShape.qml b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/windowCursorShape.qml
new file mode 100644
index 0000000000..b5c1f3d2ef
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/windowCursorShape.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.15
+import QtQuick.Window 2.15
+
+Window {
+ width: 320
+ height: 240
+ visible: true
+ color: hh.hovered ? "lightsteelblue" : "beige"
+ HoverHandler {
+ id: hh
+ cursorShape: Qt.OpenHandCursor
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp b/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp
index 11a5393390..c3429456ae 100644
--- a/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp
@@ -62,6 +62,7 @@ private slots:
void hoverHandlerAndUnderlyingMouseArea();
void movingItemWithHoverHandler();
void margin();
+ void window();
private:
void createView(QScopedPointer<QQuickView> &window, const char *fileName);
@@ -363,6 +364,28 @@ void tst_HoverHandler::margin() // QTBUG-85303
#endif
}
+void tst_HoverHandler::window() // QTBUG-98717
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("windowCursorShape.qml"));
+ QScopedPointer<QQuickWindow> window(qobject_cast<QQuickWindow *>(component.create()));
+ QVERIFY(!window.isNull());
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+#if QT_CONFIG(cursor)
+ if (isPlatformWayland())
+ QSKIP("Wayland: QCursor::setPos() doesn't work.");
+#ifdef Q_OS_MACOS
+ QSKIP("macOS: QCursor::setPos() doesn't work (QTBUG-76312).");
+#endif
+ auto cursorPos = window->mapToGlobal(QPoint(100, 100));
+ qCDebug(lcPointerTests) << "in window @" << window->position() << "setting cursor pos" << cursorPos;
+ QCursor::setPos(cursorPos);
+ QTRY_COMPARE(window->cursor().shape(), Qt::OpenHandCursor);
+#endif
+}
+
QTEST_MAIN(tst_HoverHandler)
#include "tst_qquickhoverhandler.moc"
diff --git a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
index 0e6c3b3ad9..30d57b9c9a 100644
--- a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
+++ b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
@@ -383,6 +383,7 @@ void tst_QQuickAccessible::basicPropertiesTest()
QCOMPARE(item->indexOfChild(text2), 1);
QCOMPARE(text2->state().editable, 0u);
QCOMPARE(text2->state().readOnly, 1);
+ QCOMPARE(text2->state().focusable, 1);
QCOMPARE(iface->indexOfChild(text2), -1);
QCOMPARE(text2->indexOfChild(item), -1);
diff --git a/tests/auto/quick/qquickanimations/BLACKLIST b/tests/auto/quick/qquickanimations/BLACKLIST
new file mode 100644
index 0000000000..6c1bec6520
--- /dev/null
+++ b/tests/auto/quick/qquickanimations/BLACKLIST
@@ -0,0 +1,3 @@
+# See qtbase/src/testlib/qtestblacklist.cpp for format
+[reparent]
+ci macos # QTBUG-108880
diff --git a/tests/auto/quick/qquickanimations/data/cleanupWhenRenderThreadStops.qml b/tests/auto/quick/qquickanimations/data/cleanupWhenRenderThreadStops.qml
new file mode 100644
index 0000000000..4cfb59aeab
--- /dev/null
+++ b/tests/auto/quick/qquickanimations/data/cleanupWhenRenderThreadStops.qml
@@ -0,0 +1,32 @@
+//main.qml
+
+import QtQuick 2.12
+import QtQuick.Window 2.12
+
+Item {
+ id: root
+ width: 640
+ height: 480
+ visible: true
+ property bool running : false
+
+ Rectangle {
+ id: rect
+ anchors.fill: parent
+ color: "red"
+
+ Component.onCompleted: {
+ anim.start()
+ running = true
+ }
+ }
+
+ OpacityAnimator {
+ id: anim
+
+ target: rect
+ from: 1
+ to: 0
+ duration: 20000
+ }
+}
diff --git a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
index 9b5710bad4..95af4a0560 100644
--- a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
+++ b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
@@ -116,6 +116,7 @@ private slots:
void fastFlickingBug();
void opacityAnimationFromZero();
void alwaysRunToEndInSequentialAnimationBug();
+ void cleanupWhenRenderThreadStops();
};
#define QTIMED_COMPARE(lhs, rhs) do { \
@@ -1998,6 +1999,19 @@ void tst_qquickanimations::alwaysRunToEndInSequentialAnimationBug()
QCOMPARE(whiteRect->property("opacity").value<qreal>(),1.0);
}
+void tst_qquickanimations::cleanupWhenRenderThreadStops()
+{
+ QQuickView view(QUrl::fromLocalFile("data/cleanupWhenRenderThreadStops.qml"));
+ view.show();
+ view.setPersistentOpenGLContext(false);
+ view.setPersistentSceneGraph(false);
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+ QTest::qWait(50);
+ view.hide();
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+}
+
QTEST_MAIN(tst_qquickanimations)
#include "tst_qquickanimations.moc"
diff --git a/tests/auto/quick/qquickbehaviors/BLACKLIST b/tests/auto/quick/qquickbehaviors/BLACKLIST
new file mode 100644
index 0000000000..d2a11a6a32
--- /dev/null
+++ b/tests/auto/quick/qquickbehaviors/BLACKLIST
@@ -0,0 +1,3 @@
+# See qtbase/src/testlib/qtestblacklist.cpp for format
+[currentValue]
+ci macos # QTBUG-108258
diff --git a/tests/auto/quick/qquickdroparea/BLACKLIST b/tests/auto/quick/qquickdroparea/BLACKLIST
new file mode 100644
index 0000000000..0967969b04
--- /dev/null
+++ b/tests/auto/quick/qquickdroparea/BLACKLIST
@@ -0,0 +1,4 @@
+# Blacklist for testing
+# QTBUG-99765
+[containsDrag_internal]
+ubuntu-20.04
diff --git a/tests/auto/quick/qquickflickable/data/contentPosWhileDragging.qml b/tests/auto/quick/qquickflickable/data/contentPosWhileDragging.qml
new file mode 100644
index 0000000000..57a4273257
--- /dev/null
+++ b/tests/auto/quick/qquickflickable/data/contentPosWhileDragging.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.14
+
+Item {
+ id: root
+ width: 500
+ height: 500
+ Flickable {
+ anchors.centerIn: parent
+ width: 100
+ height: 100
+ clip: true
+ contentWidth: content.width
+ contentHeight: content.height
+ Rectangle {
+ id: content
+ width: 320
+ height: width
+ color: "#41cd52"
+ radius: width/2
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
index f3659290eb..62f7c67dd4 100644
--- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
+++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
@@ -27,10 +27,10 @@
****************************************************************************/
#include <qtest.h>
#include <QtTest/QSignalSpy>
+#include <QtQuick/qquickview.h>
#include <QtGui/QStyleHints>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
-#include <QtQuick/qquickview.h>
#include <private/qquickflickable_p.h>
#include <private/qquickflickable_p_p.h>
#include <private/qquickmousearea_p.h>
@@ -206,6 +206,8 @@ private slots:
void synchronousDrag_data();
void synchronousDrag();
void visibleAreaBinding();
+ void setContentPositionWhileDragging_data();
+ void setContentPositionWhileDragging();
private:
void flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to);
@@ -870,6 +872,7 @@ void tst_qquickflickable::wheel()
QVERIFY(flick != nullptr);
QQuickFlickablePrivate *fp = QQuickFlickablePrivate::get(flick);
QSignalSpy moveEndSpy(flick, SIGNAL(movementEnded()));
+ quint64 timestamp = 10;
// test a vertical flick
{
@@ -877,6 +880,7 @@ void tst_qquickflickable::wheel()
QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(), QPoint(0,-120),
Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
event.setAccepted(false);
+ event.setTimestamp(timestamp);
QGuiApplication::sendEvent(window.data(), &event);
}
@@ -887,6 +891,7 @@ void tst_qquickflickable::wheel()
QCOMPARE(fp->velocityTimeline.isActive(), false);
QCOMPARE(fp->timeline.isActive(), false);
QTest::qWait(50); // make sure that onContentYChanged won't sneak in again
+ timestamp += 50;
QCOMPARE(flick->property("movementsAfterEnd").value<int>(), 0); // QTBUG-55886
// get ready to test horizontal flick
@@ -900,8 +905,8 @@ void tst_qquickflickable::wheel()
QPoint pos(200, 200);
QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(), QPoint(-120,0),
Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
-
event.setAccepted(false);
+ event.setTimestamp(timestamp);
QGuiApplication::sendEvent(window.data(), &event);
}
@@ -926,11 +931,13 @@ void tst_qquickflickable::trackpad()
QVERIFY(flick != nullptr);
QSignalSpy moveEndSpy(flick, SIGNAL(movementEnded()));
QPoint pos(200, 200);
+ quint64 timestamp = 10;
{
QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(0,-100), QPoint(0,-120),
Qt::NoButton, Qt::NoModifier, Qt::ScrollBegin, false);
event.setAccepted(false);
+ event.setTimestamp(timestamp++);
QGuiApplication::sendEvent(window.data(), &event);
}
@@ -944,6 +951,7 @@ void tst_qquickflickable::trackpad()
QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(-100,0), QPoint(-120,0),
Qt::NoButton, Qt::NoModifier, Qt::ScrollUpdate, false);
event.setAccepted(false);
+ event.setTimestamp(timestamp++);
QGuiApplication::sendEvent(window.data(), &event);
}
@@ -954,6 +962,7 @@ void tst_qquickflickable::trackpad()
QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(0,0), QPoint(0,0),
Qt::NoButton, Qt::NoModifier, Qt::ScrollEnd, false);
event.setAccepted(false);
+ event.setTimestamp(timestamp++);
QGuiApplication::sendEvent(window.data(), &event);
}
@@ -2551,6 +2560,115 @@ void tst_qquickflickable::visibleAreaBinding()
// Shouldn't crash.
}
+void tst_qquickflickable::setContentPositionWhileDragging_data()
+{
+ QTest::addColumn<bool>("isHorizontal");
+ QTest::addColumn<int>("newPos");
+ QTest::addColumn<int>("newExtent");
+ QTest::newRow("horizontal, setContentX") << true << 0 << -1;
+ QTest::newRow("vertical, setContentY") << false << 0 << -1;
+ QTest::newRow("horizontal, setContentWidth") << true << -1 << 200;
+ QTest::newRow("vertical, setContentHeight") << false << -1 << 200;
+}
+
+void tst_qquickflickable::setContentPositionWhileDragging() // QTBUG-104966
+{
+ QFETCH(bool, isHorizontal);
+ QFETCH(int, newPos);
+ QFETCH(int, newExtent);
+
+ QScopedPointer<QQuickView> window(new QQuickView);
+ window->setSource(testFileUrl("contentPosWhileDragging.qml"));
+ QTRY_COMPARE(window->status(), QQuickView::Ready);
+ QQuickViewTestUtil::centerOnScreen(window.data());
+ QQuickViewTestUtil::moveMouseAway(window.data());
+ window->show();
+ QVERIFY(QTest::qWaitForWindowActive(window.data()));
+ QQuickItem *rootItem = window->rootObject();
+ QVERIFY(rootItem);
+
+ QVERIFY(window->isVisible());
+ QQuickFlickable *flickable = rootItem->findChild<QQuickFlickable *>();
+ QVERIFY(flickable);
+
+ const auto contentPos = [flickable]() -> QPoint {
+ return QPoint(flickable->contentX(), flickable->contentY());
+ };
+ const qreal threshold =
+ qApp->styleHints()->startDragDistance() * flickable->parentItem()->scale();
+ const QPoint thresholdPnt(qRound(threshold), qRound(threshold));
+ const auto flickableCenterPos = flickable->mapToScene({flickable->width() / 2, flickable->height() / 2}).toPoint();
+
+ // Drag the mouse until we have surpassed the mouse drag threshold and a drag is initiated
+ // by checking for flickable->isDragging()
+ QPoint pos = flickableCenterPos;
+ moveAndPress(window.data(), pos);
+ int j = 1;
+ QVERIFY(!flickable->isDragging());
+ while (!flickable->isDragging()) {
+ pos = flickableCenterPos - QPoint(j, j);
+ QTest::mouseMove(window.data(), pos);
+ j++;
+ }
+
+ // Now we have entered the drag state
+ QVERIFY(flickable->isDragging());
+ QCOMPARE(flickable->contentX(), 0);
+ QCOMPARE(flickable->contentY(), 0);
+ QVERIFY(flickable->width() > 0);
+ QVERIFY(flickable->height() > 0);
+
+
+ const int moveLength = 50;
+ const QPoint unitDelta(isHorizontal ? 1 : 0, isHorizontal ? 0 : 1);
+ const QPoint moveDelta = unitDelta * moveLength;
+
+ pos -= 3*moveDelta;
+ QTest::mouseMove(window.data(), pos);
+ // Should be positive because we drag in the opposite direction
+ QCOMPARE(contentPos(), 3 * moveDelta);
+ QPoint expectedContentPos;
+
+ // Set the content item position back to zero *while dragging* (!!)
+ if (newPos >= 0) {
+ if (isHorizontal) {
+ flickable->setContentX(newPos);
+ } else {
+ flickable->setContentY(newPos);
+ }
+ // Continue dragging
+ pos -= moveDelta;
+ expectedContentPos = moveDelta;
+ } else if (newExtent >= 0) {
+ // ...or reduce the content size be be less than current (contentX, contentY) position
+ // This forces the content item to move.
+ // contentY: 150
+ // 320 - 150 = 170 pixels down to bottom
+ // Now reduce contentHeight to 200
+ // since we are at the bottom, and the flickable is 100 pixels tall, contentY must land
+ // at newExtent - 100.
+
+ if (isHorizontal) {
+ flickable->setContentWidth(newExtent);
+ } else {
+ flickable->setContentHeight(newExtent);
+ }
+ // Assumption is that the contentItem is aligned to the bottom of the flickable
+ // We therefore cannot scroll/flick it further down. Drag it up towards the top instead
+ // (by moving mouse down).
+ pos += moveDelta;
+ expectedContentPos = unitDelta * (newExtent - (isHorizontal ? flickable->width() : flickable->height()));
+ }
+
+ QTest::mouseMove(window.data(), pos);
+
+ // Make sure that the contentItem was only dragged the delta in mouse movement since the last
+ // setContentX/Y() call.
+ QCOMPARE(contentPos(), expectedContentPos);
+ QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, pos);
+ QVERIFY(!flickable->isDragging());
+}
+
QTEST_MAIN(tst_qquickflickable)
#include "tst_qquickflickable.moc"
diff --git a/tests/auto/quick/qquickframebufferobject/BLACKLIST b/tests/auto/quick/qquickframebufferobject/BLACKLIST
index 93dd7e9d1c..cf30c293dd 100644
--- a/tests/auto/quick/qquickframebufferobject/BLACKLIST
+++ b/tests/auto/quick/qquickframebufferobject/BLACKLIST
@@ -1,3 +1,4 @@
+[testInvalidate)
# QTBUG-65614
b2qt
[testThatStuffWorks]
diff --git a/tests/auto/quick/qquickgridview/data/qtbug92998.qml b/tests/auto/quick/qquickgridview/data/qtbug92998.qml
new file mode 100644
index 0000000000..204e6d0b87
--- /dev/null
+++ b/tests/auto/quick/qquickgridview/data/qtbug92998.qml
@@ -0,0 +1,52 @@
+import QtQuick 2.0
+
+Item {
+ width: 450
+ height: 650
+ GridView {
+ objectName: "gridview"
+ id: gridView
+ width: 450
+ height: 650
+ layoutDirection: Qt.RightToLeft
+ property int cells: calcCells(width)
+ cellWidth: width / cells
+ cellHeight: cellWidth
+
+ delegate: Component {
+ Item {
+ width: gridView.cellWidth
+ height: gridView.cellHeight
+ Rectangle {
+ anchors {
+ fill: parent
+ margins: 10
+ }
+ color: "green"
+ }
+ }
+ }
+ model: [
+ { number: "1" },
+ { number: "2" },
+ { number: "3" },
+ { number: "4" },
+ { number: "5" },
+ { number: "6" },
+ { number: "7" },
+ { number: "8" },
+ { number: "9" },
+ { number: "10" },
+ { number: "11" },
+ { number: "12" },
+ { number: "13" },
+ { number: "14" },
+ { number: "15" },
+ { number: "16" }];
+ function calcCells(w) {
+ var rw = 120;
+ var c = Math.max(1, Math.round(w / rw));
+ return c;
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
index 46e3457d6e..94ec4f44d5 100644
--- a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
+++ b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
@@ -215,6 +215,7 @@ private slots:
void QTBUG_48870_fastModelUpdates();
void keyNavigationEnabled();
+ void resizeDynamicCellWidthRtL();
void releaseItems();
private:
@@ -6795,6 +6796,24 @@ void tst_QQuickGridView::QTBUG_48870_fastModelUpdates()
}
}
+void tst_QQuickGridView::resizeDynamicCellWidthRtL()
+{
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("qtbug92998.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "gridview");
+ QTRY_VERIFY(gridview != nullptr);
+ QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ gridview->setWidth(460);
+ QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QTRY_COMPARE(gridview->contentX(), 0.f);
+ gridview->setWidth(360);
+ QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QTRY_COMPARE(gridview->contentX(), 0.f);
+}
+
void tst_QQuickGridView::releaseItems()
{
QScopedPointer<QQuickView> view(createView());
diff --git a/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp b/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp
index 9dc9ad53ea..cb9e8d1ce2 100644
--- a/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp
+++ b/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp
@@ -72,7 +72,7 @@ private slots:
private:
QString newImageFileName() const;
- void fillRequestTestsData(const QString &id);
+ void fillRequestTestsData(const char *id);
void runTest(bool async, QQuickImageProvider *provider);
};
@@ -161,7 +161,7 @@ QString tst_qquickimageprovider::newImageFileName() const
return QString("image://test/image-%1.png").arg(count++);
}
-void tst_qquickimageprovider::fillRequestTestsData(const QString &id)
+void tst_qquickimageprovider::fillRequestTestsData(const char *id)
{
QTest::addColumn<QString>("source");
QTest::addColumn<QString>("imageId");
@@ -170,39 +170,39 @@ void tst_qquickimageprovider::fillRequestTestsData(const QString &id)
QTest::addColumn<QString>("error");
QString fileName = newImageFileName();
- QTest::newRow(QTest::toString(id + " simple test"))
+ QTest::addRow("%s simple test", id)
<< "image://test/" + fileName << fileName << "" << QSize(100,100) << "";
fileName = newImageFileName();
- QTest::newRow(QTest::toString(id + " simple test with capitalization"))//As it's a URL, should make no difference
+ QTest::addRow("%s simple test with capitalization", id)//As it's a URL, should make no difference
<< "image://Test/" + fileName << fileName << "" << QSize(100,100) << "";
fileName = newImageFileName();
- QTest::newRow(QTest::toString(id + " url with no id"))
+ QTest::addRow("%s url with no id", id)
<< "image://test/" + fileName << "" + fileName << "" << QSize(100,100) << "";
fileName = newImageFileName();
- QTest::newRow(QTest::toString(id + " url with path"))
+ QTest::addRow("%s url with path", id)
<< "image://test/test/path" + fileName << "test/path" + fileName << "" << QSize(100,100) << "";
fileName = newImageFileName();
- QTest::newRow(QTest::toString(id + " url with fragment"))
+ QTest::addRow("%s url with fragment", id)
<< "image://test/faq.html?#question13" + fileName << "faq.html?#question13" + fileName << "" << QSize(100,100) << "";
fileName = newImageFileName();
- QTest::newRow(QTest::toString(id + " url with query"))
+ QTest::addRow("%s url with query", id)
<< "image://test/cgi-bin/drawgraph.cgi?type=pie&color=green" + fileName << "cgi-bin/drawgraph.cgi?type=pie&color=green" + fileName
<< "" << QSize(100,100) << "";
fileName = newImageFileName();
- QTest::newRow(QTest::toString(id + " scaled image"))
+ QTest::addRow("%s scaled image", id)
<< "image://test/" + fileName << fileName << "sourceSize: \"80x30\"" << QSize(80,30) << "";
- QTest::newRow(QTest::toString(id + " missing"))
+ QTest::addRow("%s missing", id)
<< "image://test/no-such-file.png" << "no-such-file.png" << "" << QSize(100,100)
<< "<Unknown File>:2:1: QML Image: Failed to get image from provider: image://test/no-such-file.png";
- QTest::newRow(QTest::toString(id + " unknown provider"))
+ QTest::addRow("%s unknown provider", id)
<< "image://bogus/exists.png" << "" << "" << QSize()
<< "<Unknown File>:2:1: QML Image: Invalid image provider: image://bogus/exists.png";
}
diff --git a/tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml b/tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml
index 3a41bdb3e0..2536b9789f 100644
--- a/tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml
+++ b/tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml
@@ -51,6 +51,7 @@
import QtQuick 2.2
import QtTest 1.0
import QtQuick.Layouts 1.3
+import QtQuick.Window 2.1
Item {
id: container
@@ -103,5 +104,467 @@ Item {
layout.destroy()
}
+
+ Component {
+ id: layout_setCurrentIndex_Component
+
+ StackLayout {
+ width: 200
+ height: 200
+
+ property alias firstItem : rect
+ property alias secondItem: rowLayout
+
+ Rectangle {
+ id: rect
+ color: "red"
+ implicitWidth: 10
+ implicitHeight: 10
+ }
+ RowLayout {
+ id: rowLayout
+ spacing: 0
+ Rectangle {
+ color: "green"
+ implicitWidth: 10
+ implicitHeight: 10
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+ Rectangle {
+ color: "blue"
+ implicitWidth: 10
+ implicitHeight: 10
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+ }
+ }
+ }
+
+ function test_setCurrentIndex()
+ {
+ var layout = layout_setCurrentIndex_Component.createObject(container)
+ compare(layout.firstItem.width, 200)
+
+ // Invalidate the StackLayout (and its cached size hints)
+ layout.firstItem.implicitWidth = 42
+
+ layout.currentIndex = 1
+ compare(layout.secondItem.width, 200) // width should not be -1
+ layout.destroy()
+ }
+
+ function geometry(item) {
+ return [item.x, item.y, item.width, item.height]
+ }
+
+ Component {
+ id: countGeometryChanges_Component
+ StackLayout {
+ id: stack
+ property alias col: _col
+ property alias row: _row
+ width: 100
+ ColumnLayout {
+ id: _col
+ property alias r1: _r1
+ property alias r2: _r2
+ property alias r3: _r3
+ spacing: 0
+ property int counter : 0
+ onWidthChanged: { ++counter; }
+ Rectangle {
+ id: _r1
+ implicitWidth: 20
+ implicitHeight: 20
+ Layout.fillWidth: true
+ property int counter : 0
+ onWidthChanged: { ++counter; }
+ }
+ Rectangle {
+ id: _r2
+ implicitWidth: 50
+ implicitHeight: 50
+ Layout.fillWidth: true
+ property int counter : 0
+ onWidthChanged: { ++counter; }
+ }
+ Rectangle {
+ id: _r3
+ implicitWidth: 40
+ implicitHeight: 40
+ Layout.fillWidth: true
+ property int counter : 0
+ onWidthChanged: { ++counter; }
+ }
+ }
+ RowLayout {
+ id: _row
+ property alias r5: _r5
+ spacing: 0
+ property int counter : 0
+ onWidthChanged: { ++counter; }
+ Rectangle {
+ id: _r5
+ implicitWidth: 100
+ implicitHeight: 100
+ Layout.fillWidth: true
+ property int counter : 0
+ onWidthChanged: { ++counter; }
+ }
+ }
+ }
+ }
+
+ function test_countGeometryChanges() {
+
+ var stack = countGeometryChanges_Component.createObject(container)
+ compare(stack.currentIndex, 0)
+ compare(stack.col.width, 100)
+ compare(stack.col.height, 110)
+ compare(stack.row.width, 100)
+ compare(stack.row.height, 100)
+ verify(stack.col.r1.counter <= 2)
+ compare(stack.col.r2.counter, 1)
+ verify(stack.col.r3.counter <= 2)
+ verify(stack.col.counter <= 2)
+ compare(stack.row.counter, 1) // not visible, will only receive the initial geometry change
+ compare(stack.row.r5.counter, 0)
+ stack.destroy()
+ }
+
+
+ Component {
+ id: layoutItem_Component
+ Rectangle {
+ implicitWidth: 20
+ implicitHeight: 20
+ }
+ }
+
+ Component {
+ id: emtpy_StackLayout_Component
+ StackLayout {
+ property int num_onCountChanged: 0
+ property int num_onCurrentIndexChanged: 0
+ onCountChanged: { ++num_onCountChanged; }
+ onCurrentIndexChanged: { ++num_onCurrentIndexChanged; }
+ }
+ }
+
+ function test_addAndRemoveItems()
+ {
+ var stack = emtpy_StackLayout_Component.createObject(container)
+ stack.currentIndex = 2
+ compare(stack.implicitWidth, 0)
+ compare(stack.implicitHeight, 0)
+
+ var rect0 = layoutItem_Component.createObject(stack)
+ verify(waitForItemPolished(stack))
+ compare(stack.implicitWidth, 20)
+ compare(stack.implicitHeight, 20)
+ compare(rect0.visible, false)
+
+ var rect1 = layoutItem_Component.createObject(stack)
+ rect1.Layout.preferredWidth = 30
+ rect1.Layout.preferredHeight = 10
+ verify(waitForItemPolished(stack))
+ compare(stack.implicitWidth, 30)
+ compare(stack.implicitHeight, 20)
+ compare(rect0.visible, false)
+ compare(rect1.visible, false)
+
+ var rect2 = layoutItem_Component.createObject(stack)
+ rect2.x = 42 // ### items in a stacklayout will have their x and y positions discarded.
+ rect2.y = 42
+ rect2.Layout.preferredWidth = 80
+ rect2.Layout.preferredHeight = 30
+ rect2.Layout.fillWidth = true
+ verify(waitForItemPolished(stack))
+ compare(stack.implicitWidth, 80)
+ compare(stack.implicitHeight, 30)
+ compare(rect0.visible, false)
+ compare(rect1.visible, false)
+ compare(rect2.visible, true)
+ compare(geometry(rect2), geometry(stack))
+
+ rect2.destroy()
+ wait(0)
+ verify(waitForItemPolished(stack))
+ compare(stack.implicitWidth, 30)
+ compare(stack.implicitHeight, 20)
+
+ rect0.destroy()
+ wait(0)
+ verify(waitForItemPolished(stack))
+ compare(stack.implicitWidth, 30)
+ compare(stack.implicitHeight, 10)
+
+ rect1.destroy()
+ wait(0)
+ verify(waitForItemPolished(stack))
+ compare(stack.implicitWidth, 0)
+ compare(stack.implicitHeight, 0)
+
+ stack.destroy()
+ }
+
+ function test_sizeHint_data() {
+ return [
+ { tag: "propagateNone", layoutHints: [10, 20, 30], childHints: [11, 21, 31], expected:[10, 20, Number.POSITIVE_INFINITY]},
+ { tag: "propagateMinimumWidth", layoutHints: [-1, 20, 30], childHints: [10, 21, 31], expected:[10, 20, Number.POSITIVE_INFINITY]},
+ { tag: "propagatePreferredWidth", layoutHints: [10, -1, 30], childHints: [11, 20, 31], expected:[10, 20, Number.POSITIVE_INFINITY]},
+ { tag: "propagateMaximumWidth", layoutHints: [10, 20, -1], childHints: [11, 21, 30], expected:[10, 20, Number.POSITIVE_INFINITY]},
+ { tag: "propagateAll", layoutHints: [-1, -1, -1], childHints: [10, 20, 30], expected:[10, 20, Number.POSITIVE_INFINITY]},
+ { tag: "propagateCrazy", layoutHints: [-1, -1, -1], childHints: [40, 21, 30], expected:[30, 30, Number.POSITIVE_INFINITY]},
+ { tag: "expandMinToExplicitPref", layoutHints: [-1, 1, -1], childHints: [11, 21, 31], expected:[ 1, 1, Number.POSITIVE_INFINITY]},
+ { tag: "expandMaxToExplicitPref", layoutHints: [-1, 99, -1], childHints: [11, 21, 31], expected:[11, 99, Number.POSITIVE_INFINITY]},
+ { tag: "expandAllToExplicitMin", layoutHints: [99, -1, -1], childHints: [11, 21, 31], expected:[99, 99, Number.POSITIVE_INFINITY]},
+ { tag: "expandPrefToExplicitMin", layoutHints: [24, -1, -1], childHints: [11, 21, 31], expected:[24, 24, Number.POSITIVE_INFINITY]},
+ { tag: "boundPrefToExplicitMax", layoutHints: [-1, -1, 19], childHints: [11, 21, 31], expected:[11, 19, Number.POSITIVE_INFINITY]},
+ { tag: "boundAllToExplicitMax", layoutHints: [-1, -1, 9], childHints: [11, 21, 31], expected:[ 9, 9, Number.POSITIVE_INFINITY]},
+ ];
+ }
+
+ function itemSizeHints(item) {
+ return [item.Layout.minimumWidth, item.implicitWidth, item.Layout.maximumWidth]
+ }
+ Component {
+ id: stacklayout_sizeHint_Component
+ StackLayout {
+ property int implicitWidthChangedCount : 0
+ onImplicitWidthChanged: { ++implicitWidthChangedCount }
+ ColumnLayout {
+ Rectangle {
+ id: r1
+ color: "red"
+ Layout.minimumWidth: 1
+ Layout.preferredWidth: 2
+ Layout.maximumWidth: 3
+
+ Layout.minimumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.maximumHeight: 20
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ function test_sizeHint(data) {
+ var layout = stacklayout_sizeHint_Component.createObject(container)
+
+ var col = layout.children[0]
+ col.Layout.minimumWidth = data.layoutHints[0]
+ col.Layout.preferredWidth = data.layoutHints[1]
+ col.Layout.maximumWidth = data.layoutHints[2]
+
+ var child = col.children[0]
+ if (data.implicitWidth !== undefined) {
+ child.implicitWidth = data.implicitWidth
+ }
+ child.Layout.minimumWidth = data.childHints[0]
+ child.Layout.preferredWidth = data.childHints[1]
+ child.Layout.maximumWidth = data.childHints[2]
+
+ verify(waitForItemPolished(layout))
+ var effectiveSizeHintResult = [layout.Layout.minimumWidth, layout.implicitWidth, layout.Layout.maximumWidth]
+ compare(effectiveSizeHintResult, data.expected)
+ layout.destroy()
+ }
+
+ Component {
+ id: stacklayout_addIgnoredItem_Component
+ StackLayout {
+ Repeater {
+ id: rep
+ model: 1
+ Rectangle {
+ id: r
+ }
+ }
+ }
+ }
+
+ // Items with no size information is ignored.
+ function test_addIgnoredItem()
+ {
+ var stack = stacklayout_addIgnoredItem_Component.createObject(container)
+ compare(stack.count, 1)
+ compare(stack.implicitWidth, 0)
+ compare(stack.implicitHeight, 0)
+ var r = stack.children[0]
+ r.Layout.preferredWidth = 20
+ r.Layout.preferredHeight = 30
+ verify(waitForItemPolished(stack))
+ compare(stack.count, 1)
+ compare(stack.implicitWidth, 20)
+ compare(stack.implicitHeight, 30)
+ stack.destroy();
+ }
+
+ function test_dontCrashWhenAnchoredToAWindow() {
+ var test_layoutStr =
+ 'import QtQuick 2.2; \
+ import QtQuick.Window 2.1; \
+ import QtQuick.Layouts 1.3; \
+ Window { \
+ visible: true; \
+ width: stack.implicitWidth; \
+ height: stack.implicitHeight; \
+ StackLayout { \
+ id: stack; \
+ currentIndex: 0; \
+ anchors.fill: parent; \
+ Rectangle { \
+ color: "red"; \
+ implicitWidth: 300; \
+ implicitHeight: 200; \
+ } \
+ } \
+ } '
+
+ var win = Qt.createQmlObject(test_layoutStr, container, '');
+ if (win.visibility === Window.Windowed) {
+ // on single-window systems (such as Android), the window geometry will be
+ // fullscreen, and most likely it will be set to screen size. Avoid this test for
+ // those systems, as the size of the window will not be determined by the layout
+ tryCompare(win, 'width', 300);
+ }
+ win.destroy()
+ }
+
+ Component {
+ id: test_dontCrashWhenChildIsResizedToNull_Component
+ StackLayout {
+ property alias rect : _rect
+ Rectangle {
+ id: _rect;
+ color: "red"
+ implicitWidth: 200
+ implicitHeight: 200
+ }
+ }
+ }
+
+ function test_dontCrashWhenChildIsResizedToNull() {
+ var layout = test_dontCrashWhenChildIsResizedToNull_Component.createObject(container)
+ layout.rect.width = 0
+ layout.width = 222 // trigger a rearrange with a valid size
+ layout.height = 222
+ }
+
+ Component {
+ id: test_currentIndex_Component
+ StackLayout {
+ currentIndex: 1
+ Text {
+ text: "0"
+ }
+ Text {
+ text: "1"
+ }
+ }
+ }
+
+ function test_currentIndex() {
+ var layout = test_currentIndex_Component.createObject(container)
+ var c0 = layout.children[0]
+ var c1 = layout.children[1]
+ compare(layout.currentIndex, 1)
+ tryCompare(layout, 'visible', true)
+ compare(c0.visible, false)
+ compare(c1.visible, true)
+ layout.currentIndex = 0
+ compare(c0.visible, true)
+ compare(c1.visible, false)
+ var c2 = layoutItem_Component.createObject(layout)
+ compare(c2.visible, false)
+
+ /*
+ * destroy the current item and check if visibility advances to next
+ */
+ c0.destroy()
+ tryCompare(c1, 'visible', true)
+ compare(c2.visible, false)
+ c1.destroy()
+ tryCompare(c2, 'visible', true)
+ c2.destroy()
+ tryCompare(layout, 'currentIndex', 0)
+
+ layout.destroy()
+
+ /*
+ * Test the default/implicit value of currentIndex, either -1 (if empty) or 0:
+ */
+ layout = emtpy_StackLayout_Component.createObject(container)
+ tryCompare(layout, 'visible', true)
+ compare(layout.currentIndex, -1)
+ compare(layout.num_onCurrentIndexChanged, 0)
+ // make it non-empty
+ c0 = layoutItem_Component.createObject(layout)
+ compare(layout.currentIndex, 0)
+ compare(layout.num_onCurrentIndexChanged, 1)
+ compare(c0.visible, true)
+ // make it empty again
+ c0.destroy()
+ wait(0)
+ compare(layout.currentIndex, -1)
+ //tryCompare(layout, 'currentIndex', -1)
+ compare(layout.num_onCurrentIndexChanged, 2)
+
+ /*
+ * Check that explicit value doesn't change,
+ * and that no items are visible if the index is invalid/out of range
+ */
+ layout.currentIndex = 2
+ compare(layout.currentIndex, 2)
+ compare(layout.num_onCurrentIndexChanged, 3)
+ c0 = layoutItem_Component.createObject(layout)
+ compare(layout.currentIndex, 2)
+ compare(c0.visible, false)
+
+ c1 = layoutItem_Component.createObject(layout)
+ compare(layout.currentIndex, 2)
+ compare(c0.visible, false)
+ compare(c1.visible, false)
+
+ c2 = layoutItem_Component.createObject(layout)
+ compare(layout.currentIndex, 2)
+ compare(c0.visible, false)
+ compare(c1.visible, false)
+ compare(c2.visible, true)
+
+ c2.destroy()
+ wait(0)
+ compare(layout.currentIndex, 2)
+ compare(c0.visible, false)
+ compare(c1.visible, false)
+ c1.destroy()
+ wait(0)
+ compare(layout.currentIndex, 2)
+ compare(c0.visible, false)
+ c0.destroy()
+ wait(0)
+ compare(layout.currentIndex, 2)
+ compare(layout.num_onCurrentIndexChanged, 3)
+ }
+
+ function test_count() {
+ var layout = emtpy_StackLayout_Component.createObject(container)
+ tryCompare(layout, 'visible', true)
+ compare(layout.count, 0)
+ compare(layout.currentIndex, -1)
+ compare(layout.num_onCountChanged, 0)
+ compare(layout.num_onCurrentIndexChanged, 0)
+ var c0 = layoutItem_Component.createObject(layout)
+ compare(layout.count, 1)
+ compare(layout.currentIndex, 0)
+ compare(layout.num_onCurrentIndexChanged, 1)
+ compare(layout.num_onCountChanged, 1)
+ }
+
+
}
}
diff --git a/tests/auto/quick/qquicklistview/BLACKLIST b/tests/auto/quick/qquicklistview/BLACKLIST
index 6ef69550a4..cba2e8d752 100644
--- a/tests/auto/quick/qquicklistview/BLACKLIST
+++ b/tests/auto/quick/qquicklistview/BLACKLIST
@@ -9,6 +9,8 @@ macos
#QTBUG-75960
#QTBUG-76652
[currentIndex]
+# QTBUG-101498
+ubuntu-20
macos
opensuse-leap
ubuntu-18.04
diff --git a/tests/auto/quick/qquicklistview/data/qtbug86744.qml b/tests/auto/quick/qquicklistview/data/qtbug86744.qml
deleted file mode 100644
index 6dc82d57eb..0000000000
--- a/tests/auto/quick/qquicklistview/data/qtbug86744.qml
+++ /dev/null
@@ -1,21 +0,0 @@
-import QtQuick 2.15
-import QtQml.Models 2.15
-
-Item {
- height: 200
- width: 100
- DelegateModel {
- id: dm
- model: 2
- delegate: Item {
- width: 100; height: 20
- property bool isCurrent: ListView.isCurrentItem
- }
- }
- ListView {
- objectName: "listView"
- model: dm
- currentIndex: 1
- anchors.fill: parent
- }
-}
diff --git a/tests/auto/quick/qquicklistview/data/qtbug_92809.qml b/tests/auto/quick/qquicklistview/data/qtbug_92809.qml
new file mode 100644
index 0000000000..c0b7ac546b
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/qtbug_92809.qml
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 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: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.15
+import QtQml.Models 2.12
+
+Rectangle {
+ id: root
+ width: 800
+ height: 480
+
+ property list<QtObject> myModel: [
+ QtObject { property string name: "Item 0"; property bool selected: true },
+ QtObject { property string name: "Item 1"; property bool selected: true },
+ QtObject { property string name: "Item 2"; property bool selected: true },
+ QtObject { property string name: "Item 3"; property bool selected: true },
+ QtObject { property string name: "Item 4"; property bool selected: true },
+ QtObject { property string name: "Item 5"; property bool selected: true },
+ QtObject { property string name: "Item 6"; property bool selected: true },
+ QtObject { property string name: "Item 7"; property bool selected: true },
+ QtObject { property string name: "Item 8"; property bool selected: true },
+ QtObject { property string name: "Item 9"; property bool selected: true },
+ QtObject { property string name: "Press Enter here"; property bool selected: true }
+ ]
+
+ DelegateModel {
+ objectName: "model"
+ id: visualModel
+ model: myModel
+ filterOnGroup: "selected"
+
+ groups: [
+ DelegateModelGroup {
+ name: "selected"
+ includeByDefault: true
+ }
+ ]
+
+ delegate: Rectangle {
+ width: 180
+ height: 180
+ visible: DelegateModel.inSelected
+ color: ListView.isCurrentItem ? "orange" : "yellow"
+ Component.onCompleted: {
+ DelegateModel.inPersistedItems = true
+ DelegateModel.inSelected = Qt.binding(function() { return model.selected })
+ }
+ }
+ }
+
+ ListView {
+ objectName: "list"
+ anchors.fill: parent
+ spacing: 180/15
+ orientation: ListView.Horizontal
+ model: visualModel
+ focus: true
+ currentIndex: 0
+ preferredHighlightBegin: (width-180)/2
+ preferredHighlightEnd: (width+180)/2
+ highlightRangeMode: ListView.StrictlyEnforceRange
+ highlightMoveDuration: 300
+ highlightMoveVelocity: -1
+ cacheBuffer: 0
+
+ onCurrentIndexChanged: {
+ if (currentIndex === 10) {
+ myModel[6].selected = !myModel[6].selected
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/data/singletonModelLifetime.qml b/tests/auto/quick/qquicklistview/data/singletonModelLifetime.qml
new file mode 100644
index 0000000000..f230786723
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/singletonModelLifetime.qml
@@ -0,0 +1,32 @@
+import QtQuick 2.15
+import QtQuick.Window 2.15
+import test 1.0
+
+Window {
+ id: root
+ visible: true
+ width: 800
+ height: 680
+ property bool alive: false
+
+ Component {
+ id: view
+ ListView {
+ model: SingletonModel
+ }
+ }
+ function compare(a,b) {
+ root.alive = (a === b)
+ }
+
+ function test_singletonModelCrash() {
+ SingletonModel.objectName = "model"
+ var o = view.createObject(root)
+ o.destroy()
+ Qt.callLater(function() {
+ compare(SingletonModel.objectName, "model")
+ })
+ }
+
+ Component.onCompleted: root.test_singletonModelCrash()
+}
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index df329f8318..57d7dddf20 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -33,6 +33,8 @@
#include <QtGui/QStyleHints>
#include <QtQuick/qquickview.h>
#include <QtQuickTest/QtQuickTest>
+#include <QStringListModel>
+#include <QQmlApplicationEngine>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcontext.h>
#include <QtQml/qqmlexpression.h>
@@ -301,7 +303,10 @@ private slots:
void animatedDelegate();
void dragDelegateWithMouseArea();
void dragDelegateWithMouseArea_data();
- void isCurrentItem_DelegateModel();
+
+
+ void singletonModelLifetime();
+ void QTBUG_92809();
private:
template <class T> void items(const QUrl &source);
@@ -10201,18 +10206,48 @@ void tst_QQuickListView::dragDelegateWithMouseArea_data()
}
}
-void tst_QQuickListView::isCurrentItem_DelegateModel()
+class SingletonModel : public QStringListModel
+{
+ Q_OBJECT
+public:
+ SingletonModel(QObject* parent = nullptr) : QStringListModel(parent) { }
+};
+
+void tst_QQuickListView::singletonModelLifetime()
+{
+ // this does not really test any functionality of listview, but we do not have a good way
+ // to unit test QQmlAdaptorModel in isolation.
+ qmlRegisterSingletonType<SingletonModel>("test", 1, 0, "SingletonModel",
+ [](QQmlEngine* , QJSEngine*) -> QObject* { return new SingletonModel; });
+
+ QQmlApplicationEngine engine(testFile("singletonModelLifetime.qml"));
+ // needs event loop iteration for callLater to execute
+ QTRY_VERIFY(engine.rootObjects().first()->property("alive").toBool());
+}
+
+void tst_QQuickListView::QTBUG_92809()
{
QScopedPointer<QQuickView> window(createView());
- window->setSource(testFileUrl("qtbug86744.qml"));
- window->resize(640, 480);
+ QTRY_VERIFY(window);
+ window->setSource(testFileUrl("qtbug_92809.qml"));
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window.data()));
- QQuickListView* listView = window->rootObject()->findChild<QQuickListView*>("listView");
- QVERIFY(listView);
- QVariant value = listView->itemAtIndex(1)->property("isCurrent");
- QVERIFY(value.toBool() == true);
+ QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list");
+ QTRY_VERIFY(listview != nullptr);
+ QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ listview->setCurrentIndex(1);
+ QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ listview->setCurrentIndex(2);
+ QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ listview->setCurrentIndex(3);
+ QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QTest::qWait(500);
+ listview->setCurrentIndex(10);
+ QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QTest::qWait(500);
+ int currentIndex = listview->currentIndex();
+ QTRY_COMPARE(currentIndex, 9);
}
QTEST_MAIN(tst_QQuickListView)
diff --git a/tests/auto/quick/qquickloader/BLACKLIST b/tests/auto/quick/qquickloader/BLACKLIST
index a45a300607..aeb3674482 100644
--- a/tests/auto/quick/qquickloader/BLACKLIST
+++ b/tests/auto/quick/qquickloader/BLACKLIST
@@ -1,4 +1,5 @@
# Test fails on qemu when bound to one core, passes on real ARM
# QTBUG-63049
[asyncToSync1]
+ci ubuntu-20.04 # QTBUG-106424
b2qt
diff --git a/tests/auto/quick/qquickloader/data/noEngine.qml b/tests/auto/quick/qquickloader/data/noEngine.qml
new file mode 100644
index 0000000000..19e619f32e
--- /dev/null
+++ b/tests/auto/quick/qquickloader/data/noEngine.qml
@@ -0,0 +1,32 @@
+import QtQuick 2
+
+Item {
+ id: root
+ property bool a: false
+ property int changes: 0
+ onAChanged: {
+ m.model = 0
+ m.model = 1
+ ++changes;
+ }
+
+ Repeater {
+ id: m
+ model: 1
+
+ Item {
+ Timer {
+ onTriggered: {
+ root.a = true
+ l.source = "loaded.qml"
+ }
+ interval: 0
+ running: true
+ }
+
+ Loader {
+ id: l
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickloader/data/overflow.qml b/tests/auto/quick/qquickloader/data/overflow.qml
new file mode 100644
index 0000000000..8ca196e2ed
--- /dev/null
+++ b/tests/auto/quick/qquickloader/data/overflow.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.15
+
+Loader {
+ source: "overflow.qml"
+}
diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
index dddacbaa0b..4539a89cb3 100644
--- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp
+++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
@@ -133,6 +133,9 @@ private slots:
void setSourceAndCheckStatus();
void asyncLoaderRace();
+ void noEngine();
+
+ void stackOverflow();
};
Q_DECLARE_METATYPE(QList<QQmlError>)
@@ -1515,6 +1518,31 @@ void tst_QQuickLoader::asyncLoaderRace()
QCOMPARE(loader->item(), nullptr);
}
+void tst_QQuickLoader::noEngine()
+{
+ QQmlEngine engine;
+ const QUrl url = testFileUrl("noEngine.qml");
+ QQmlComponent component(&engine, url);
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ QScopedPointer<QObject> o(component.create());
+
+ const QString message = url.toString()
+ + QStringLiteral(":27:13: QML Loader: createComponent: Cannot find a QML engine.");
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(message));
+ QTRY_COMPARE(o->property("changes").toInt(), 1);
+}
+
+void tst_QQuickLoader::stackOverflow()
+{
+ QQmlEngine engine;
+ const QUrl url = testFileUrl("overflow.qml");
+ QQmlComponent component(&engine, url);
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ const QString message = url.toString() + QStringLiteral(": Maximum call stack size exceeded.");
+ QTest::ignoreMessage(QtCriticalMsg, qPrintable(message));
+ QScopedPointer<QObject> o(component.create());
+}
+
QTEST_MAIN(tst_QQuickLoader)
#include "tst_qquickloader.moc"
diff --git a/tests/auto/quick/qquickmousearea/data/doubleClickToHide.qml b/tests/auto/quick/qquickmousearea/data/doubleClickToHide.qml
new file mode 100644
index 0000000000..01f6eaabed
--- /dev/null
+++ b/tests/auto/quick/qquickmousearea/data/doubleClickToHide.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property int clicked: 0
+ property int doubleClicked: 0
+ property int released: 0
+
+ MouseArea {
+ width: 200; height: 200
+ onClicked: { root.clicked++ }
+ onDoubleClicked: {
+ root.doubleClicked++
+ visible = false
+ }
+ onReleased: { root.released++ }
+ }
+}
+
diff --git a/tests/auto/quick/qquickmousearea/data/preventStealingListViewChild.qml b/tests/auto/quick/qquickmousearea/data/preventStealingListViewChild.qml
new file mode 100644
index 0000000000..3833c5a8a9
--- /dev/null
+++ b/tests/auto/quick/qquickmousearea/data/preventStealingListViewChild.qml
@@ -0,0 +1,31 @@
+import QtQuick 2.15
+
+ListView {
+ id: flick
+ width: 640
+ height: 480
+ model: 100
+
+ delegate: Rectangle {
+ border.color: "#81e889"
+ width: 640; height: 100
+ Text { text: "Row " + index }
+ }
+
+ Rectangle {
+ anchors.right: parent.right
+ anchors.margins: 2
+ color: ma.pressed ? "#81e889" : "#c2f4c6"
+ width: 50; height: 50
+ radius: 5
+ MouseArea {
+ id: ma
+ anchors.fill: parent
+ preventStealing: true
+ drag {
+ target: parent
+ axis: Drag.YAxis
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
index 1c99357ab7..941d6dc47b 100644
--- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
+++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
@@ -129,6 +129,7 @@ private slots:
void invalidClick();
void pressedOrdering();
void preventStealing();
+ void preventStealingListViewChild();
void clickThrough();
void hoverPosition();
void hoverPropagation();
@@ -161,6 +162,7 @@ private slots:
void nestedEventDelivery();
void settingHiddenInPressUngrabs();
void containsMouseAndVisibility();
+ void doubleClickToHide();
private:
int startDragDistance() const {
@@ -1211,6 +1213,39 @@ void tst_QQuickMouseArea::preventStealing()
QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, p);
}
+// QTBUG-103522
+void tst_QQuickMouseArea::preventStealingListViewChild()
+{
+ QQuickView window;
+ QByteArray errorMessage;
+ QVERIFY2(QQuickTest::initView(window, testFileUrl("preventStealingListViewChild.qml"), true, &errorMessage), errorMessage.constData());
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window.rootObject());
+ QVERIFY(flickable);
+ QQuickMouseArea *mouseArea = flickable->findChild<QQuickMouseArea*>();
+ QVERIFY(mouseArea);
+ QPoint p = mouseArea->mapToScene(mouseArea->boundingRect().center()).toPoint();
+ const int threshold = qApp->styleHints()->startDragDistance();
+
+ flickable->flick(0, -10000);
+ for (int i = 0; i < 2; ++i) {
+ QVERIFY(flickable->isMovingVertically());
+ QTest::touchEvent(&window, device).press(0, p);
+ QQuickTouchUtils::flush(&window);
+ for (int j = 0; j < 4 && !mouseArea->drag()->active(); ++j) {
+ p += QPoint(0, threshold);
+ QTest::touchEvent(&window, device).move(0, p);
+ QQuickTouchUtils::flush(&window);
+ }
+ // MouseArea should be dragged because of preventStealing; ListView does not steal the grab.
+ QVERIFY(mouseArea->drag()->active());
+ QCOMPARE(flickable->isDragging(), false);
+ QTest::touchEvent(&window, device).release(0, p);
+ QCOMPARE(mouseArea->drag()->active(), false);
+ }
+}
+
void tst_QQuickMouseArea::clickThrough()
{
//With no handlers defined click, doubleClick and PressAndHold should propagate to those with handlers
@@ -2500,6 +2535,33 @@ void tst_QQuickMouseArea::containsMouseAndVisibility()
QVERIFY(!mouseArea->hovered());
}
+// QTBUG-35995 and QTBUG-102158
+void tst_QQuickMouseArea::doubleClickToHide()
+{
+ QQuickView window;
+ QByteArray errorMessage;
+ QVERIFY2(QQuickTest::initView(window, testFileUrl("doubleClickToHide.qml"), true, &errorMessage), errorMessage.constData());
+ window.show();
+ window.requestActivate();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+
+ QQuickMouseArea *mouseArea = window.rootObject()->findChild<QQuickMouseArea *>();
+ QVERIFY(mouseArea);
+
+ QTest::mouseDClick(&window, Qt::LeftButton, Qt::NoModifier, {10, 10});
+
+ QCOMPARE(window.rootObject()->property("clicked").toInt(), 1);
+ QCOMPARE(window.rootObject()->property("doubleClicked").toInt(), 1);
+ QCOMPARE(mouseArea->isVisible(), false);
+ QCOMPARE(mouseArea->pressed(), false);
+ QCOMPARE(mouseArea->pressedButtons(), Qt::NoButton);
+
+ mouseArea->setVisible(true);
+
+ QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, {10, 10});
+ QCOMPARE(window.rootObject()->property("clicked").toInt(), 2);
+}
+
QTEST_MAIN(tst_QQuickMouseArea)
#include "tst_qquickmousearea.moc"
diff --git a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST
index 6af00ab76f..db8595544b 100644
--- a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST
+++ b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST
@@ -1,10 +1,14 @@
[nonOverlapping]
+# QTBUG-101499
+ubuntu-20.04
ubuntu-16.04
ubuntu-18.04
opensuse-42.3
opensuse-leap
sles
[nested]
+# QTBUG-101499
+ubuntu-20.04
ubuntu-16.04
ubuntu-18.04
opensuse-42.3
diff --git a/tests/auto/quick/qquickmultipointtoucharea/data/nestedMouseArea.qml b/tests/auto/quick/qquickmultipointtoucharea/data/nestedMouseArea.qml
new file mode 100644
index 0000000000..7ca3f187d6
--- /dev/null
+++ b/tests/auto/quick/qquickmultipointtoucharea/data/nestedMouseArea.qml
@@ -0,0 +1,26 @@
+import QtQuick 2.12
+
+Item {
+ id: root
+ width: 300; height: 300
+ property point mptaPoint
+ property point maPoint
+ MultiPointTouchArea {
+ anchors.fill : parent
+ onPressed: function(touchPoints) {
+ root.mptaPoint = Qt.point(touchPoints[0].x, touchPoints[0].y)
+ }
+ MouseArea {
+ id: ma
+ width: 100; height: 100
+ anchors.centerIn: parent
+ onPressed: function(mouse) {
+ root.maPoint = Qt.point(mouse.x, mouse.y)
+ }
+ }
+ Rectangle {
+ anchors.fill: ma
+ border.color: "grey"
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickmultipointtoucharea/data/nestedPinchArea.qml b/tests/auto/quick/qquickmultipointtoucharea/data/nestedPinchArea.qml
new file mode 100644
index 0000000000..0e51804b30
--- /dev/null
+++ b/tests/auto/quick/qquickmultipointtoucharea/data/nestedPinchArea.qml
@@ -0,0 +1,44 @@
+import QtQuick 2.15
+
+MultiPointTouchArea {
+ width: 240
+ height: 320
+ mouseEnabled: true
+ property int pressedCount: 0
+ property int updatedCount: 0
+ property int releasedCount: 0
+
+ onPressed: (points) => { pressedCount = points.length }
+ onUpdated: (points) => { updatedCount = points.length }
+ onReleased: (points) => { releasedCount = points.length }
+
+ touchPoints: [
+ TouchPoint {
+ id: point1
+ objectName: "point1"
+ },
+ TouchPoint {
+ id: point2
+ objectName: "point2"
+ }
+ ]
+
+ PinchArea {
+ anchors.fill: parent
+ }
+
+ Rectangle {
+ width: 30; height: 30
+ color: "green"
+ x: point1.x
+ y: point1.y
+ }
+
+ Rectangle {
+ id: rectangle
+ width: 30; height: 30
+ color: "yellow"
+ x: point2.x
+ y: point2.y
+ }
+}
diff --git a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp
index c18a220996..3aff9a293a 100644
--- a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp
+++ b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp
@@ -77,6 +77,8 @@ private slots:
void mouseGestureStarted();
void cancel();
void stationaryTouchWithChangingPressure();
+ void nestedPinchAreaMouse();
+ void touchFiltering();
private:
QQuickView *createAndShowView(const QString &file);
@@ -1408,6 +1410,70 @@ void tst_QQuickMultiPointTouchArea::stationaryTouchWithChangingPressure() // QTB
QCOMPARE(point1->pressure(), 0);
}
+void tst_QQuickMultiPointTouchArea::nestedPinchAreaMouse()
+{
+ QScopedPointer<QQuickView> window(createAndShowView("nestedPinchArea.qml"));
+ QQuickMultiPointTouchArea *mpta = qobject_cast<QQuickMultiPointTouchArea *>(window->rootObject());
+ QVERIFY(mpta);
+
+ QQuickTouchPoint *point1 = mpta->findChild<QQuickTouchPoint*>("point1");
+ QCOMPARE(point1->pressed(), false);
+ QQuickTouchPoint *point2 = mpta->findChild<QQuickTouchPoint*>("point2");
+ QCOMPARE(point2->pressed(), false);
+ QSignalSpy pressedSpy(mpta, &QQuickMultiPointTouchArea::pressed);
+ QSignalSpy updatedSpy(mpta, &QQuickMultiPointTouchArea::updated);
+ QSignalSpy releasedSpy(mpta, &QQuickMultiPointTouchArea::released);
+
+ QPoint p1(20, 20);
+ QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, p1);
+ QCOMPARE(point1->pressed(), true);
+ QCOMPARE(point2->pressed(), false);
+ QCOMPARE(pressedSpy.count(), 1);
+ QCOMPARE(mpta->property("pressedCount").toInt(), 1);
+ QCOMPARE(updatedSpy.count(), 0);
+ QCOMPARE(mpta->property("updatedCount").toInt(), 0);
+ QCOMPARE(releasedSpy.count(), 0);
+ QCOMPARE(mpta->property("releasedCount").toInt(), 0);
+
+ p1 += QPoint(0, 15);
+ QTest::mouseMove(window.data(), p1);
+ QCOMPARE(point1->pressed(), true);
+ QCOMPARE(point2->pressed(), false);
+ QCOMPARE(pressedSpy.count(), 1);
+ QCOMPARE(mpta->property("pressedCount").toInt(), 1);
+ QCOMPARE(updatedSpy.count(), 1);
+ QCOMPARE(mpta->property("updatedCount").toInt(), 1);
+ QCOMPARE(releasedSpy.count(), 0);
+ QCOMPARE(mpta->property("releasedCount").toInt(), 0);
+
+ QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, p1);
+ QCOMPARE(point1->pressed(), false);
+ QCOMPARE(point2->pressed(), false);
+ QCOMPARE(pressedSpy.count(), 1);
+ QCOMPARE(mpta->property("pressedCount").toInt(), 1);
+ QCOMPARE(updatedSpy.count(), 1);
+ QCOMPARE(mpta->property("updatedCount").toInt(), 1);
+ QCOMPARE(releasedSpy.count(), 1);
+ QCOMPARE(mpta->property("releasedCount").toInt(), 1);
+}
+
+void tst_QQuickMultiPointTouchArea::touchFiltering() // QTBUG-74028
+{
+ QScopedPointer<QQuickView> window(createAndShowView("nestedMouseArea.qml"));
+ QVERIFY(window->rootObject() != nullptr);
+ QQuickMultiPointTouchArea *mpta = window->rootObject()->findChild<QQuickMultiPointTouchArea*>();
+ QVERIFY(mpta);
+ QQuickMouseArea *ma = window->rootObject()->findChild<QQuickMouseArea*>();
+ QVERIFY(ma);
+
+ QSignalSpy mptaSpy(mpta, &QQuickMultiPointTouchArea::pressed);
+ const QPoint pt = window->rootObject()->boundingRect().center().toPoint();
+ QTest::touchEvent(window.data(), device).press(1, pt);
+ QQuickTouchUtils::flush(window.data());
+ QTRY_COMPARE(mpta->parentItem()->property("mptaPoint").toPoint(), pt);
+ QCOMPARE(mpta->parentItem()->property("maPoint").toPoint(), ma->boundingRect().center().toPoint());
+ QCOMPARE(mptaSpy.count(), 1);
+}
QTEST_MAIN(tst_QQuickMultiPointTouchArea)
diff --git a/tests/auto/quick/qquickstates/data/noStateOsciallation.qml b/tests/auto/quick/qquickstates/data/noStateOsciallation.qml
new file mode 100644
index 0000000000..f0d7aeeb6d
--- /dev/null
+++ b/tests/auto/quick/qquickstates/data/noStateOsciallation.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.15
+
+Item {
+ id: root
+ property int number: 2
+ property int stateChangeCounter: 0
+
+ Item {
+ id: item
+ onStateChanged: ++stateChangeCounter
+ states: [
+ State {
+ name: "n1"
+ when: root.number === 1
+ },
+ State {
+ name: "n2"
+ when: root.number === 2
+ }
+ ]
+ }
+}
diff --git a/tests/auto/quick/qquickstates/tst_qquickstates.cpp b/tests/auto/quick/qquickstates/tst_qquickstates.cpp
index 849522454f..aa55b42935 100644
--- a/tests/auto/quick/qquickstates/tst_qquickstates.cpp
+++ b/tests/auto/quick/qquickstates/tst_qquickstates.cpp
@@ -188,6 +188,7 @@ private slots:
void revertListMemoryLeak();
void duplicateStateName();
void trivialWhen();
+ void noStateOsciallation();
void parentChangeCorrectReversal();
void revertNullObjectBinding();
};
@@ -1733,6 +1734,20 @@ void tst_qquickstates::trivialWhen()
QVERIFY(c.create());
}
+void tst_qquickstates::noStateOsciallation()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("noStateOsciallation.qml"));
+ QScopedPointer<QObject> root {component.create()};
+ QVERIFY(root);
+ // set to 1 on initial transition from "" to "n2"
+ QCOMPARE(root->property("stateChangeCounter").toInt(), 1);
+ root->setProperty("number", 1);
+ // setting number to 1 changes directly from "n2" to "n1"
+ // without any intermediate transition to ""
+ QCOMPARE(root->property("stateChangeCounter").toInt(), 2);
+}
+
void tst_qquickstates::parentChangeCorrectReversal()
{
QQmlEngine engine;
diff --git a/tests/auto/quick/qquicktext/data/fontSizeMode.qml b/tests/auto/quick/qquicktext/data/fontSizeMode.qml
index 48e7c7b6d0..d5e794824f 100644
--- a/tests/auto/quick/qquicktext/data/fontSizeMode.qml
+++ b/tests/auto/quick/qquicktext/data/fontSizeMode.qml
@@ -16,7 +16,7 @@ Item {
height: 35
minimumPointSize: 8
minimumPixelSize: 8
- font.pixelSize: 25
+ font.pixelSize: 23
font.family: "Helvetica"
}
}
diff --git a/tests/auto/quick/qquicktext/data/padding.qml b/tests/auto/quick/qquicktext/data/padding.qml
index ab0a37d041..f830af0e40 100644
--- a/tests/auto/quick/qquicktext/data/padding.qml
+++ b/tests/auto/quick/qquicktext/data/padding.qml
@@ -9,4 +9,30 @@ Text {
leftPadding: 30
rightPadding: 40
bottomPadding: 50
+
+ Rectangle {
+ width: parent.leftPadding
+ height: parent.height
+ color: "#6600FF00"
+ }
+
+ Rectangle {
+ width: parent.width
+ height: parent.topPadding
+ color: "#66888800"
+ }
+
+ Rectangle {
+ x: parent.width - parent.rightPadding
+ width: parent.rightPadding
+ height: parent.height
+ color: "#6600FFFF"
+ }
+
+ Rectangle {
+ y: parent.height - parent.bottomPadding
+ width: parent.width
+ height: parent.bottomPadding
+ color: "#66880088"
+ }
}
diff --git a/tests/auto/quick/qquicktext/data/paddingInLoader.qml b/tests/auto/quick/qquicktext/data/paddingInLoader.qml
new file mode 100644
index 0000000000..6ef7c25a9b
--- /dev/null
+++ b/tests/auto/quick/qquicktext/data/paddingInLoader.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.12
+
+Item {
+ width: 30
+ height: 30
+ Loader {
+ anchors.fill: parent
+ sourceComponent: Text {
+ rightPadding: 30
+ text: "Some text"
+ elide: Text.ElideRight
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
index fe3f696dfa..03570b43ce 100644
--- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp
+++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
@@ -55,6 +55,8 @@ QT_BEGIN_NAMESPACE
extern void qt_setQtEnableTestFont(bool value);
QT_END_NAMESPACE
+Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
+
class tst_qquicktext : public QQmlDataTest
{
Q_OBJECT
@@ -153,6 +155,7 @@ private slots:
void growFromZeroWidth();
void padding();
+ void paddingInLoader();
void hintingPreference();
@@ -3475,6 +3478,46 @@ void tst_qquicktext::fontSizeMode()
myText->setElideMode(QQuickText::ElideNone);
QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+
+ // Growing height needs to update the baselineOffset when AlignBottom is used
+ // and text is NOT wrapped
+ myText->setVAlign(QQuickText::AlignBottom);
+ myText->setFontSizeMode(QQuickText::Fit);
+ QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+
+ int baselineOffset = myText->baselineOffset();
+ myText->setHeight(myText->height() * 2);
+ QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(myText->baselineOffset() > baselineOffset);
+
+ // Growing height needs to update the baselineOffset when AlignBottom is used
+ // and the text is wrapped
+ myText->setVAlign(QQuickText::AlignBottom);
+ myText->setFontSizeMode(QQuickText::Fit);
+ myText->setWrapMode(QQuickText::NoWrap);
+ myText->resetMaximumLineCount();
+ QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+
+ baselineOffset = myText->baselineOffset();
+ myText->setHeight(myText->height() * 2);
+ QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(myText->baselineOffset() > baselineOffset);
+
+ // Check baselineOffset for the HorizontalFit case
+ myText->setVAlign(QQuickText::AlignBottom);
+ myText->setFontSizeMode(QQuickText::HorizontalFit);
+ QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QSignalSpy baselineOffsetSpy(myText, SIGNAL(baselineOffsetChanged(qreal)));
+ QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ const qreal oldBaselineOffset = myText->baselineOffset();
+ myText->setHeight(myText->height() + 42);
+ QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QCOMPARE(baselineOffsetSpy.count(), 1);
+ QCOMPARE(myText->baselineOffset(), oldBaselineOffset + 42);
+ myText->setHeight(myText->height() - 42);
+ QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QCOMPARE(baselineOffsetSpy.count(), 2);
+ QCOMPARE(myText->baselineOffset(), oldBaselineOffset);
}
void tst_qquicktext::fontSizeModeMultiline_data()
@@ -4342,6 +4385,20 @@ void tst_qquicktext::padding()
obj->setElideMode(QQuickText::ElideRight);
QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding());
QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding());
+
+ obj->setLeftPadding(0);
+ QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding());
+
+ obj->setWidth(cw);
+ obj->setRightPadding(cw);
+ QCOMPARE(obj->contentWidth(), 0);
+
+ for (int incr = 1; incr < 50 && qFuzzyIsNull(obj->contentWidth()); ++incr)
+ obj->setWidth(cw + incr);
+ QVERIFY(obj->contentWidth() > 0);
+ qCDebug(lcTests) << "increasing Text width from" << cw << "to" << obj->width()
+ << "rendered a character: contentWidth now" << obj->contentWidth();
+
obj->setElideMode(QQuickText::ElideNone);
obj->resetWidth();
@@ -4386,6 +4443,34 @@ void tst_qquicktext::padding()
delete root;
}
+void tst_qquicktext::paddingInLoader() // QTBUG-83413
+{
+ QQuickView view(testFileUrl("paddingInLoader.qml"));
+ view.show();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+ QQuickText *qtext = view.rootObject()->findChild<QQuickText*>();
+ QVERIFY(qtext);
+ QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(qtext);
+ QVERIFY(textPrivate);
+ QCOMPARE(qtext->contentWidth(), 0); // does not render text, because width == rightPadding
+ QCOMPARE(textPrivate->availableWidth(), 0);
+
+ qtext->setLeftPadding(qtext->width());
+ qtext->setRightPadding(0);
+ QCOMPARE(qtext->contentWidth(), 0); // does not render text, because width == leftPadding
+ QCOMPARE(textPrivate->availableWidth(), 0);
+
+ qtext->setRightPadding(qtext->width());
+ QCOMPARE(qtext->contentWidth(), 0); // does not render text: available space is negative
+ QCOMPARE(textPrivate->availableWidth(), -qtext->width());
+
+ qtext->setLeftPadding(2);
+ qtext->setRightPadding(2);
+ QVERIFY(qtext->contentWidth() > 0); // finally space is available to render text
+ QCOMPARE(textPrivate->availableWidth(), qtext->width() - 4);
+}
+
void tst_qquicktext::hintingPreference()
{
{
diff --git a/tests/auto/quick/qquickvisualdatamodel/data/setDelegateNoDoubleChange.qml b/tests/auto/quick/qquickvisualdatamodel/data/setDelegateNoDoubleChange.qml
new file mode 100644
index 0000000000..05623fbc5b
--- /dev/null
+++ b/tests/auto/quick/qquickvisualdatamodel/data/setDelegateNoDoubleChange.qml
@@ -0,0 +1,43 @@
+import QtQuick 2.0
+
+Item {
+ width: 200
+ height: 200
+ id: root
+ property int creationCount: 0
+ property bool testStarted: false
+
+ ListModel {
+ id: mymodel
+ ListElement {message: "This is my alarm"}
+ }
+
+ Component {
+ id: aDelegate
+ Rectangle {
+ color: "blue"
+ width: 100
+ height: 100
+ }
+ }
+
+ Component {
+ id: bDelegate
+ Rectangle {
+ color: "red"
+ width: 100
+ height: 100
+ Text {text: model.message }
+ Component.onCompleted: root.creationCount++
+ }
+ }
+
+
+ ListView {
+ width: 200
+ height: 200
+ id: myListView
+ model: mymodel
+ delegate: testStarted ? bDelegate : aDelegate
+ }
+}
diff --git a/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp b/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp
index 27bd8aae49..83bdb1a5f8 100644
--- a/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp
+++ b/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp
@@ -434,6 +434,7 @@ private slots:
void invalidContext();
void externalManagedModel();
void delegateModelChangeDelegate();
+ void noDoubleDelegateUpdate();
void checkFilterGroupForDelegate();
void readFromProxyObject();
@@ -4345,6 +4346,20 @@ void tst_qquickvisualdatamodel::delegateModelChangeDelegate()
QCOMPARE(visualModel->count(), 3);
}
+void tst_qquickvisualdatamodel::noDoubleDelegateUpdate()
+{
+ // changing a delegate only refreshes its instances once
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("setDelegateNoDoubleChange.qml"));
+
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY(root);
+
+ bool ok = root->setProperty("testStarted", true);
+ QVERIFY(ok);
+ QCOMPARE(root->property("creationCount").toInt(), 1);
+}
+
void tst_qquickvisualdatamodel::checkFilterGroupForDelegate()
{
QQuickView view;
diff --git a/tests/baseline/scenegraph/data/text/text_nativerendering_no_antialiasing.qml b/tests/baseline/scenegraph/data/text/text_nativerendering_no_antialiasing.qml
new file mode 100644
index 0000000000..92598eb490
--- /dev/null
+++ b/tests/baseline/scenegraph/data/text/text_nativerendering_no_antialiasing.qml
@@ -0,0 +1,25 @@
+import QtQuick 2.0
+
+//vary font style, native rendering without antialiasing
+
+Item {
+ id: topLevel
+ width: 320
+ height: 580
+
+ Repeater {
+ model: [Text.Normal, Text.Outline, Text.Raised, Text.Sunken]
+ Text {
+ y: 20 * index
+ clip: true
+ renderType: Text.NativeRendering
+ width: parent.width
+ wrapMode: Text.Wrap
+ font.pointSize: 10
+ style: modelData
+ styleColor: "green"
+ antialiasing: false
+ text: "The quick fox jumps in style " + modelData
+ }
+ }
+}
diff --git a/tests/manual/touch/flicktext.qml b/tests/manual/touch/flicktext.qml
index 9e84261687..e69d6207a9 100644
--- a/tests/manual/touch/flicktext.qml
+++ b/tests/manual/touch/flicktext.qml
@@ -380,6 +380,36 @@ Rectangle {
text: "content X " + flick.contentX.toFixed(2) + " Y " + flick.contentY.toFixed(2)
}
}
+
+ Column {
+ Row {
+ spacing: 2
+ Examples.Button {
+ id: decrButton
+ text: "-"
+ onClicked: flick.flickDeceleration -= 100
+ Timer {
+ running: decrButton.pressed
+ interval: 100; repeat: true
+ onTriggered: flick.flickDeceleration -= 100
+ }
+ }
+ Text {
+ horizontalAlignment: Text.AlignHCenter
+ text: "decel:\n" + flick.flickDeceleration.toFixed(4)
+ }
+ Examples.Button {
+ id: incrButton
+ text: "+"
+ onClicked: flick.flickDeceleration += 100
+ }
+ Timer {
+ running: incrButton.pressed
+ interval: 100; repeat: true
+ onTriggered: flick.flickDeceleration += 100
+ }
+ }
+ }
}
Component.onCompleted: {
diff --git a/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in b/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in
index 26d42c02a9..8a91fb8b87 100644
--- a/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in
+++ b/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in
@@ -40,6 +40,7 @@ but not all the files it references.
set(rcc_files ${_RCC_UNPARSED_ARGUMENTS})
set(rcc_options ${_RCC_OPTIONS})
set(filtered_rcc_files)
+ set(output_resources)
set(compiler_output)
set(rcc_files_with_compilation_units)
set(loader_flags)
@@ -52,13 +53,15 @@ but not all the files it references.
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${input_resource}")
execute_process(COMMAND ${compiler_path} --filter-resource-file ${input_resource} -o ${new_resource_file} OUTPUT_VARIABLE remaining_files)
- list(APPEND filtered_rcc_files ${new_resource_file})
- list(APPEND loader_flags \"--resource-file-mapping=${_resource}=${new_resource_file}\")
set(rcc_file_with_compilation_units)
execute_process(COMMAND ${rcc_path} -list \"${input_resource}\" OUTPUT_VARIABLE rcc_contents)
if (NOT rcc_contents STREQUAL \"\")
+
+ list(APPEND filtered_rcc_files ${new_resource_file})
+ list(APPEND loader_flags \"--resource-file-mapping=${_resource}=${new_resource_file}\")
+
string(REGEX REPLACE \"[\r\n]+\" \";\" rcc_contents ${rcc_contents})
foreach(it ${rcc_contents})
get_filename_component(extension ${it} EXT)
@@ -85,6 +88,8 @@ but not all the files it references.
list(APPEND compiler_output ${loader_source})
endif()
- qt5_add_resources(output_resources ${filtered_rcc_files} OPTIONS ${rcc_options})
+ if(filtered_rcc_files)
+ qt5_add_resources(output_resources ${filtered_rcc_files} OPTIONS ${rcc_options})
+ endif()
set(${outfiles} ${output_resources} ${compiler_output} PARENT_SCOPE)
endfunction()
diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp
index bc74e7b08e..050dd95e45 100644
--- a/tools/qmlcachegen/qmlcachegen.cpp
+++ b/tools/qmlcachegen/qmlcachegen.cpp
@@ -135,7 +135,7 @@ static void annotateListElements(QmlIR::Document *document)
if (!listElementNames.contains(document->stringAt(object->inheritedTypeNameIndex)))
continue;
for (QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Script)
+ if (binding->type() != QV4::CompiledData::Binding::Type_Script)
continue;
binding->stringIndex = document->registerString(object->bindingAsString(document, binding->value.compiledScriptIndex));
}
@@ -146,7 +146,7 @@ static bool checkArgumentsObjectUseInSignalHandlers(const QmlIR::Document &doc,
{
for (QmlIR::Object *object: qAsConst(doc.objects)) {
for (auto binding = object->bindingsBegin(); binding != object->bindingsEnd(); ++binding) {
- if (binding->type != QV4::CompiledData::Binding::Type_Script)
+ if (binding->type() != QV4::CompiledData::Binding::Type_Script)
continue;
const QString propName = doc.stringAt(binding->propertyNameIndex);
if (!propName.startsWith(QLatin1String("on"))
diff --git a/tools/qmlimportscanner/main.cpp b/tools/qmlimportscanner/main.cpp
index 5e3f41e8c6..8209236916 100644
--- a/tools/qmlimportscanner/main.cpp
+++ b/tools/qmlimportscanner/main.cpp
@@ -74,18 +74,18 @@ inline QString directoryLiteral() { return QStringLiteral("directory"); }
void printUsage(const QString &appNameIn)
{
- const std::wstring appName = appNameIn.toStdWString();
+ const std::string appName = appNameIn.toStdString();
#ifndef QT_BOOTSTRAPPED
const QString qmlPath = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath);
#else
const QString qmlPath = QStringLiteral("/home/user/dev/qt-install/qml");
#endif
- std::wcerr
+ std::cerr
<< "Usage: " << appName << " -rootPath path/to/app/qml/directory -importPath path/to/qt/qml/directory\n"
" " << appName << " -qmlFiles file1 file2 -importPath path/to/qt/qml/directory\n"
" " << appName << " -qrcFiles file1.qrc file2.qrc -importPath path/to/qt/qml/directory\n\n"
"Example: " << appName << " -rootPath . -importPath "
- << QDir::toNativeSeparators(qmlPath).toStdWString()
+ << QDir::toNativeSeparators(qmlPath).toStdString()
<< '\n';
}
diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp
index b87b55283a..21d04df853 100644
--- a/tools/qmlplugindump/main.cpp
+++ b/tools/qmlplugindump/main.cpp
@@ -991,19 +991,9 @@ bool compactDependencies(QStringList *dependencies)
return false;
}
-inline std::wostream &operator<<(std::wostream &str, const QString &s)
-{
-#ifdef Q_OS_WIN
- str << reinterpret_cast<const wchar_t *>(s.utf16());
-#else
- str << s.toStdWString();
-#endif
- return str;
-}
-
void printDebugMessage(QtMsgType, const QMessageLogContext &, const QString &msg)
{
- std::wcerr << msg << std::endl;
+ std::cerr << msg.toStdString() << std::endl;
// In case of QtFatalMsg the calling code will abort() when appropriate.
}